A.膜法记录
二进制枚举行的状态,可以只枚举二进制1个数为a的状态。
#include<bits/stdc++.h> using namespace std; int main(){ int t;cin>>t; while(t--){ int n,m,a,b; scanf("%d%d%d%d",&n,&m,&a,&b); string s[n]; for(int i=0;i<n;i++)cin>>s[i]; vector<int>v; for(int i=0;i<1<<n;i++){ int x=__builtin_popcount(i); if(x==a)v.push_back(i); } function<bool(int x)>fun=[&](int x){ vector<string>p; for(int i=0;i<n;i++){ if(!(x>>i&1))p.push_back(s[i]); } int sz=p.size(); int ans=0; for(int j=0;j<m;j++){ bool l=0; for(int i=0;i<sz&&!l;i++){ l|=p[i][j]=='*'; } ans+=l; } return ans<=b; }; bool f=0; for(int &x:v){ if(fun(x)){ f=1; puts("yes");break; } } if(!f)puts("no"); } }
B.阶乘
二分判断。
#include<bits/stdc++.h> using namespace std; int main(){ int t;cin>>t; while(t--){ int p;scanf("%d",&p); if(p==1) { puts("1");continue; } vector<pair<int,int> >v; for(int i=2;i*i<=p;i++){ if(p%i==0){ int cnt=0; while(p%i==0)p/=i,cnt++; v.push_back({i,cnt}); } } if(p>1)v.push_back({p,1}); if(v.size()==1&&v[0].second==1){ printf("%d\n",p);continue; } int sz=v.size(); function<bool(int mid)>ck=[&](int mid){ for(int i=0;i<sz;i++){ int ans=mid,cnt=0; int x=v[i].first; while(ans)cnt+=ans/=x; if(cnt>=v[i].second)continue; return 0; } return 1; }; int l=v[sz-1].first,r=1e9+7; int ans=l; while(l<=r){ int mid=l+r>>1; if(ck(mid))ans=mid,r=mid-1; else l=mid+1; } printf("%d\n",ans); } }
C.完全图
二分长度即可。
#include<bits/stdc++.h> using namespace std; typedef long long ll; int main(){ int t;cin>>t; while(t--){ ll x,y;scanf("%lld%lld",&x,&y); __int128 n=x,m=y; if((m>=n*(n-1)/2)){ printf("%lld\n",x); continue; } __int128 l=1,k=1,r=n; while(r>=l){ __int128 mid=l+r>>1; __int128 x=mid*(mid+1)/2; if(n*mid-x<=m)k=mid,l=mid+1; else r=mid-1; } while(n*k-k*(k+1)/2<=m)k++; if(n*k-k*(k+1)/2>m)k--; printf("%lld\n",(ll)k+1); } }
E.A+B问题
puts("4294967296");
G.树上求和
一棵树上经过一条边的路径数等于两端点节点数之积。
#include<bits/stdc++.h> using namespace std; const int N=1e5+5; int n; vector<int>g[N]; vector<long long >v; int dp[N]; void dfs(int u,int fa){ dp[u]=1; for(int v:g[u]){ if(v==fa)continue; dfs(v,u); dp[u]+=dp[v]; } } void Dfs(int u,int fa){ if(fa){ v.push_back(1LL*dp[u]*(dp[fa]-dp[u])); dp[u]=dp[fa]; } for(int v:g[u]){ if(v==fa)continue; Dfs(v,u); } } int main(){ cin>>n; for(int i=1;i<n;i++){ int u,v; scanf("%d%d",&u,&v); g[u].push_back(v); g[v].push_back(u); } dfs(1,0);Dfs(1,0); sort(v.begin(),v.end()); long long ans=0; for(int i=0,k=n-1;i<n-1;i++,k--){ ans+=v[i]*k; } printf("%lld\n",ans); }
H.奇怪的背包问题增加了
从大到小合并,可以利用栈来实现。
#include<bits/stdc++.h> using namespace std; const int N=1e5+5; int n; int k[N],a[N],s[N],tp=0; int f[32]; int main(){ int t;cin>>t; while(t--){ scanf("%d",&n); memset(f,0,sizeof f);tp=0; for(int i=0;i++<n;scanf("%d",&k[i]),a[i]=k[i]); sort(a+1,a+1+n,greater<int>()); for(int i=1;i<=n;i++){ int v=a[i]; while(tp&&s[tp]==v)v++,tp--; s[++tp]=v;f[a[i]]++; if(s[1]==30)break; } if(s[1]!=30)printf("impossible\n"); else{ for(int i=1;i<=n;i++){ if(f[k[i]])f[k[i]]--,putchar('1'); else putchar('0'); } putchar(10); } } }
I.寻找子串
尺取。
#include<bits/stdc++.h> using namespace std; string KP(string s) { int st = 0; int len = s.size(); for(int i = 1; i < len; i++) { int sz = 0; while(i+sz < len && s[st + sz] == s[i + sz]) { sz++; } if(s[i + sz] > s[st + sz]) st = i; if(i+sz == len) break; } return s.substr(st); } int main(){ string a; cin>>a; cout<<KP(a)<<endl; }
J.最大的差
MAX-MIN