week5
Day1
2023牛客寒假算法基础集训营4
A—清楚姐姐学信息论
思路:比较pow(x, y)和pow(y, x)大小
#include <bits/stdc++.h> using namespace std; int main() { long long int a, g,n; cin >> a >> g; if (pow(a,g) <pow(g,a)) { cout << g << endl; } else if (pow(a,g) > pow(g,a)) { cout << a <<endl; } else cout<< min(a,g)<<endl; return 0; }
B-清楚姐姐学构造
思路:当m为2,且前后的c的和为奇数时不存在;先构造出a,为前后c的和的一半时可满足条件,(特判下前后c的和为奇数时,可能存在a同b不同的情况)再用c,a求出b;
#include<iostream> using namespace std; typedef long long ll; const int N=1e5+5; int n,m; ll c[N],a[N],b[N]; int main(){ scanf("%d %d",&n,&m); for(int i=0;i<n;++i) scanf("%lld",&c[i]); for(int i=0;i<n;++i){ ll sum=c[i]+c[n-1-i]; if(sum%2&&m==2){ printf("No"); return 0; }else if(sum%2) a[i]=((sum+m)/2)%m; else a[i]=(sum/2)%m; } for(int i=0;i<n;++i) b[i]=(((c[i]-a[i])%m)+m)%m; if(n%2){ a[n/2]=c[n/2]; b[n/2]=0; } printf("Yes\n"); for(int i=0;i<n;++i) printf("%lld ",a[i]); cout<<endl; for(int i=0;i<n;++i) printf("%lld ",b[i]); }
C—清楚姐姐学01背包(Easy Version)
思路:把除了第i个物品以外的物品打一个01背包,判断第i个物品是否必须取
#include <bits/stdc++.h> using namespace std; using LL = long long; int main(){ int T = 1; while(T--){ int n,m; cin>>n>>m; vector<int> v(n+1),w(n+1); for(int i=1;i<=n;i++){ cin>>w[i]>>v[i]; } for(int i=1;i<=n;i++){ vector<LL> dp(m+1); for(int j=1;j<=n;j++){ if(i==j) continue; for(int k=m;k>=w[j];k--){ dp[k] = max(dp[k] , dp[k-w[j]] + v[j]); } } LL ans = dp[m]-dp[m-w[i]] - v[i] + 1; if(ans<0) cout<<0<<endl; else cout<<ans<<endl; } } return 0; }
E—清楚姐姐打怪升级
思路:若在一次时间间隔内的恢复量大于等于攻击力则杀不死
#include<bits/stdc++.h> using namespace std; const int N=1e5+5,M=1e9; typedef long long ll; ll n,t,a,h,v,s=1; int main(){ cin>>n>>t>>a; bool ok=true; for(int i=0;i<n;++i){ cin>>h>>v; h-=a,s+=t; if(h<=0)continue; if(t*v>=a){ cout<<"-1";return 0; } else{ s+=(h/(a-v*t))*t; if(h%(a-v*t))s+=t; } } cout<<s-t; return 0; }
L—清楚姐姐的三角形I
思路:由公式求出三边,保证三条边为整数,再判断三边是否构成三角形
#include<bits/stdc++.h> using namespace std; const int N=1e5+5,M=1e9; int t; typedef long long ll; int main(){ cin>>t; ll a,b,c,aa,bb,cc; while(t--){ bool ok=true; cin>>a>>b>>c; if((a+c-b)%2||(b+c-a)%2||(a+b-c)%2)ok=false; else{ bb=(a+c-b)/2; aa=(b+c-a)/2; cc=(a+b-c)/2; } if(!ok||((aa+bb)<=cc||(bb+cc)<=aa||(aa+cc)<=bb))cout<<"No\n"; else { cout<<"Yes\n"; cout<<aa<<' '<<bb<<' '<<cc<<'\n'; } } return 0; }
M—清楚姐姐的三角形II
思路:循环11212...
#include <iostream> using namespace std; int main() { int n; cin>>n; for(int i=0;i<n;i++){ if((i+1)%3!=0){ cout<<"1"; }else{ cout<<"2"; } if(i!=n-1){ cout<<" "; } } }
Day 3
SMU Winter 2023 Round #9 (Div.2)
A-Who is The 19th ZUCCPC Champion
#include<bits/stdc++.h> using namespace std; const int N=3e4+5,M=1e5+5; typedef long long ll; int main(){ cin.tie(0),cout.tie(0); cout<<"Ranni the Witch"; return 0; }
B-Jiubei and Overwatch
思路:找出最大的ai,判断与k*x的关系,求出最小ans
#include<bits/stdc++.h> using namespace std; const int N=3e4+5,M=1e5+5; typedef long long ll; int t,n,k,x,y,ma,m; int main(){ cin.tie(0),cout.tie(0); cin>>t; while(t--){ cin>>n>>k>>x>>y; ma=0; for(int i=0;i<n;++i){ cin>>m; ma=max(ma,m); } int res=0; if(ma<=k*x){ res+=(ma/x); if(ma%x)res++; } else{ res+=k; ma-=(k*x); res+=(ma/y); if(ma%y)res++; } cout<<res<<'\n'; } return 0; }
C-Ah, It's Yesterday Once More
思路:倒序输出n个数
#include<bits/stdc++.h> using namespace std; const int N=3e4+5,M=1e5+5; typedef long long ll; int t,n; int main(){ cin.tie(0),cout.tie(0); cin>>t; while(t--){ cin>>n; for(int i=n;i>=1;--i)cout<<i<<' '; cout<<'\n'; } return 0; }
F-Sum of Numerators
思路:k为0时,分子为1,2,3,...,n;k为1时,分子中偶数都除2,新的分子需减去1,2,...,n/2;依次减下去...直到k次或没有偶数(n为0)
#include<bits/stdc++.h> using namespace std; const int N=5e3+5,M=1e5+5; typedef long long ll; ll t,n,k; int main(){ cin.tie(0),cout.tie(0); cin>>t; while(t--){ cin>>n>>k; ll s=(1+n)*n/2; for(int i=1;i<=k&&n!=0;++i){ n/=2; s-=(1+n)*n/2; } cout<<s<<'\n'; } return 0; }
G-Guaba and Computational Geometry
思路:对x轴上的线段进行左端点排序,从左到右对于每个左端点,统计出右端点小于左端点的线段的最大w;同理求出y轴上的最大w;取最大w
#include <bits/stdc++.h> #define int long long using namespace std; const int N = 1e6 + 5, mod = 1e9 + 7; struct node{ int x1, x2; int val; bool operator < (const node &k) const { return x1 < k.x1; } }a[N]; struct P{ int a, b, c, d; int val; } b[N]; struct t{ int b, val; bool operator < (const t &k) const{ return b > k.b; } }; priority_queue<t> q; int get(int n) { int ret = 0; int ma = -1; for (int i = 1; i <= n; i++) { while(!q.empty() && q.top().b < a[i].x1) { ma = max(ma, q.top().val); q.pop(); } if (ma != -1) ret = max(ret, ma + a[i].val); q.push(t{a[i].x2, a[i].val}); } while (!q.empty()) q.pop(); return ret; } void solve() { int n; cin >> n; for (int i = 1; i <= n; i++) { scanf("%lld%lld%lld%lld", &b[i].a, &b[i].b, &b[i].c, &b[i].d); } for (int i = 1; i <= n; i++) { scanf("%lld", &b[i].val); } for (int i = 1; i <= n; i++) { a[i].x1 = b[i].a, a[i].x2 = b[i].c; a[i].val = b[i].val; } sort(a + 1, a + 1 + n); int ans = 0; ans = max(ans, get(n)); for (int i = 1; i <= n; i++) { a[i].x1 = b[i].b, a[i].x2 = b[i].d; a[i].val = b[i].val; } sort(a + 1, a + 1 + n); ans = max(ans, get(n)); if (ans != 0) printf("%lld\n", ans); else puts("-1"); } signed main() { int tt = 1; cin >> tt; while (tt--) solve(); return 0; }
I-Array Division
思路:求出ai与bi的差的前缀和,dp求出以1为左端,n为右端的区间段最大个数
#include<bits/stdc++.h> using namespace std; const int N=5e3+5,M=1e5+5; typedef long long ll; ll t,n,a[N],b[N],d[N],p[N]; int main(){ cin.tie(0),cout.tie(0); cin>>t; while(t--){ cin>>n; d[0]=p[0]=0; for(int i=1;i<=n;++i)cin>>a[i]; for(int i=1;i<=n;++i)cin>>b[i],d[i]=a[i]-b[i],d[i]+=d[i-1]; for(int i=1;i<=n;++i)p[i]=-1; for(int i=0;i<=n;++i){ if(p[i]==-1)continue; for(int j=i+1;j<=n;++j) if(d[j]-d[i]>=0)p[j]=max(p[j],p[i]+1); } cout<<p[n]<<'\n'; } return 0; }
J-Substring Inversion (Easy Version)
思路:将所有子字符串排列,并记录左端点,从小到大标记每个子字符串的左端点,每次求出从该左端点往右中已标记过的子字符串个数
#include<bits/stdc++.h> using namespace std; const int N=410,M=1e9+7; typedef long long ll; ll t,n; string s; int a[N]; vector<pair<string,int> >ve; int main(){ cin.tie(0),cout.tie(0); cin>>t; while(t--){ ve.clear(); cin>>n>>s; string ss=s; for(int i=0;i<n;++i){ a[i]=0; for(int j=i;j<n;++j){ ve.push_back({ss.substr(i,j-i+1),i}); ss=s; } } sort(ve.begin(),ve.end()); ll res=0; for(int i=0;i<ve.size();++i){ int j=ve[i].second; for(int k=j+1;k<n;++k)res+=a[k]; a[j]++; } cout<<res%M<<'\n'; } return 0; }
L-Monster Tower
思路:用小顶堆维护k个数,若堆顶小于总量,则总量加堆顶,否则更新x,x=堆顶-总量,x取最大
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N = 2e5+10; ll t,n,k; ll a[N]; priority_queue<ll,vector<int>,greater<int> >q; ll sta,now; int main() { cin >> t; while (t--) { cin >> n >> k; sta = 0; now = 0; for (int i = 1; i <= n; i++) { scanf("%lld", &a[i]); } for (int i = 1; i <= n; i++) { if (q.empty() || q.size() < k) q.push(a[i]);//注意判空 else { ll s = q.top(); q.pop(); if (now >= s) now += s; else { sta = max(sta, s - now); now += s; q.push(a[i]); } } } while (!q.empty()) { ll s = q.top(); q.pop(); if (now >= s) now += s; else { sta = max(sta, s - now); now += s; } } cout << sta << endl; } return 0; }
Day 5
2023牛客寒假算法基础集训营6
A-阿宁的签到题
#include <bits/stdc++.h> using namespace std; #define ll long long #define endl '\n' const int N=1e5+10; const int mod=1e9+7; int main() { ll x; cin>>x; if(1<=x&&x<=7)cout<<"very easy"; else if(7<x&&x<=233)cout<<"easy"; else if(233<x&&x<=10032)cout<<"medium"; else if(10032<x&&x<=114514)cout<<"hard"; else if(114514<x&&x<=1919810)cout<<"very hard"; else if(1919810<x)cout<<"can not imagine"; return 0; }
B-阿宁的倍数
思路:每次统计每个数的因数的个数,及每个数的倍数的前缀和,答案为倍数的总个数 - 该数前的倍数个数
#include <bits/stdc++.h> #define ll long long using namespace std; const int N = 2e5 + 5, M = 1e9 + 7; int n,q,f[N]; int main(){ cin.tie(0),cout.tie(0); cin>>n>>q; vector<int>a(n+1),p(n+1); for(int i=1;i<=n;++i){ cin>>a[i]; for(int j=1;j*j<=a[i];++j){ if(a[i]%j==0){ f[j]++; if(j*j!=a[i])f[a[i]/j]++; } } p[i]=f[a[i]]; } int o,x; while(q--){ cin>>o>>x; if(o==1){ a.push_back(x); for(int i=1;i*i<=x;++i){ if(x%i==0){ f[i]++; if(i*i!=x)f[x/i]++; } } p.push_back(f[a.back()]); } else cout<<f[a[x]]-p[x]<<'\n'; } return 0; }
C-阿宁的大背包
思路:中间取最大,依次往两边减小
#include <bits/stdc++.h> #define ll long long using namespace std; const int N = 1e3 + 5, M = 1e9 + 7; ll n,a[N],b[N]; int main(){ cin.tie(0),cout.tie(0); cin>>n; ll x=(n+1)/2,y=x+1,s=n; while(x>0||y<=n){ if(x>0)a[x--]=s--; if(y<=n)a[y++]=s--; } for(int i=1;i<=n;++i)b[i]=a[i]; for(int i=n-1;i>=1;--i){ for(int j=1;j<=i;++j){ b[j]=(b[j]+b[j+1])%M; } }cout<<b[1]%M<<'\n'; for(int i=1;i<=n;++i)cout<<a[i]<<' '; return 0; }
D-阿宁的毒瘤题
思路:求u的前缀和、后缀和,求每个d前u个数的前缀和、每个d后u个数的后缀和;
枚举字符串,为d时,减少的数量为 前u个数 * 后u个数;为u时,减少的个数为 前每个d前u个数和 + 后每个d后的u个数和;
标记减少数量最大的位置即为答案
#include <bits/stdc++.h> #define ll long long using namespace std; const int N = 2e5 + 5, M = 1e9 + 7; string s; ll l[N],r[N],dl[N],dr[N],ss,s1; int main(){ cin.tie(0),cout.tie(0); cin>>s; for(int i=0;i<s.size();++i){ if(s[i]=='u')ss++; l[i]=ss; if(s[i]=='d')s1+=l[i]; dl[i]=s1; } ss=s1=0; for(int i=s.size()-1;i>=0;--i){ if(s[i]=='u')ss++; r[i]=ss; if(s[i]=='d')s1+=r[i]; dr[i]=s1; } ll ma=-1,t,a; for(int i=0;i<s.size();++i){ a=0; if(s[i]=='d'){ a=l[i]*r[i]; } if(s[i]=='u'){ a=dl[i]+dr[i]; } if(a>ma){ ma=a,t=i; } } s[t]='x'; cout<<s; return 0; }
E-阿宁的生成树
思路:大于k+1的点到点1的边权都为1,剩余的一一枚举出最小的gcd(),每次为1时结束
#include <bits/stdc++.h> #define ll long long using namespace std; const int N = 2e5 + 5, M = 1e9 + 7; int n,k; int main() { cin.tie(0), cout.tie(0); cin>>n>>k; ll s=min(n,k+1); ll ans=n-s; for(int i=2;i<=s;++i){ ll a=i; for(int j=i+k+1;j<=n;++j){ a=min(a,(ll)__gcd(i,j)); if(a==1)break; } ans+=a; } cout<<ans; return 0; }
F-阿宁的二进制
思路:用大顶堆维护所有数,将所有不为1的数进行转换,记录每次转换后的堆顶
#include <bits/stdc++.h> #define ll long long using namespace std; const int N = 2e5 + 5, M = 1e9 + 7; int n,q,k,s[10*N]; priority_queue<int>qe; int lowbit(int x){ return x&(-x); } int main(){ cin.tie(0),cout.tie(0); cin>>n>>q; int a; for(int i=0;i<n;++i){ cin>>a; if(a!=1) qe.push(a); } s[0]=0; while(!qe.empty()){ int t=qe.top();qe.pop(); if(t==1)break; int res=0; while(t)t-=lowbit(t),res++; qe.push(res); s[++s[0]]=qe.top(); } while(q--){ cin>>a; if(s[0]==0)cout<<1<<'\n'; else if(a>s[0])cout<<s[s[0]]<<'\n'; else cout<<s[a]<<'\n'; } return 0; }
G-阿宁的整数配对
思路:分别对正数、负数以绝对值进行排序,类归并排序选取对数
#include <bits/stdc++.h> #define ll long long using namespace std; const int N = 2e5 + 5, mod = 1e9 + 7; int n,k,a[N],b[N]; bool cmp(int x,int y){ return x>y; } int main(){ cin.tie(0),cout.tie(0); cin>>n>>k; int t; a[0]=b[0]=0; for(int i=1;i<=n;++i){ cin>>t; if(t>=0)a[++a[0]]=t; else b[++b[0]]=t*(-1); } sort(a+1,a+a[0]+1,cmp),sort(b+1,b+b[0]+1,cmp); ll aa,bb,xx=0,yy=0; ll s=0; for(int i=1;i<=k;++i){ aa=bb=0; if(a[0]>=2)aa=a[xx+1]*a[xx+2]; if(b[0]>=2)bb=b[yy+1]*b[yy+2]; if(a[0]<2&&b[0]<2){ aa=a[xx+1]*b[yy+1]; s-=aa;break; } if(aa>=bb){ a[0]-=2; xx+=2;s+=aa; } else{ b[0]-=2; yy+=2;s+=bb; } } cout<<s; return 0; }
H-阿宁讨伐虚空
思路:在l~r中找出小于x的个数
#include <bits/stdc++.h> #define ll long long using namespace std; const int N = 1e6 + 5, mod = 1e9 + 7; int main(){ cin.tie(0),cout.tie(0); ll x,l,r,a,b; double s; cin>>x>>l>>r; if(x<l)s=0; else if(x>r)s=1; else{ a=x-l,b=r-l+1; s=double(a)/double(b); } cout<<fixed<<setprecision(16)<<s; return 0; }
I-阿宁前往沙城
思路:走过的路也可删,直接求1到n的最短路,若仅有一条路径,则只有第一条不可删掉,时间为该路权值,其余都为1;若多条路径,所有路都为1
#include<bits/stdc++.h> #define endl '\n' #define int long long using namespace std; const int N=2e5+3; vector<pair<int ,int >>g[N]; int a[N]; void solve() { int n,m; cin>>n>>m; for(int i=1; i<=m; i++) { int u,v,w; cin>>u>>v>>w; g[u].push_back({v,w}),g[v].push_back({u,w}); } queue<int >q; a[1]=1; q.push(1); while(!q.empty()) { int x=q.front(); q.pop(); for(auto [i,j] :g[x]) { if(a[i]==0) a[i]=a[x]+1,q.push(i); } } if(a[n]-1!=m) cout<<a[n]-1; else cout<<a[n]-2+g[1][0].second; } signed main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); solve(); return 0; }
L-阿宁睡大觉
思路:总数为2n-1,一个噩梦所占数量:经过该点的次数 * 2(n -(x+y)+ 1),减去每行列数最小的噩梦(某些噩梦所占路线可能一样 )
Day 6
第十届图灵杯NEUQ-ACM程序设计竞赛个人赛
A-有用的算法
思路:看序列是否有序
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e6+10; int n,a[N],b=0; int main(){ cin>>n; for(int i=0;i<n;++i){ cin>>a[i]; } for(int i=0;i<n;++i){ if(i!=0&&(a[i]<a[i-1])){ b=1;break; } } if(b==1){ for(int i=0;i<n;++i){ if(i!=0&&a[i]>a[i-1]){ b=2;break; } } } if(b==0||b==1)cout<<"erfen is useful!"; else cout<<"bukeyi"; return 0; }
B-平衡数
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=2e5+10; int main(){ int t,n; cin>>t; while(t--){ cin>>n; int a,b,c,d; a=n/1000; b=n/100-a*10; c=n/10-a*100-b*10; d=n%10; if((a+b)==(c+d))cout<<"YES\n"; else cout<<"NO\n"; } return 0; }
C-三角形
思路:求出边AC和边CB的线性方程,将点代入,判断是否超出范围
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e6+10; int main(){ double xb,xc,yc,k1,k2,b2,xp,yp,y1,y2; cin>>xb>>xc>>yc>>xp>>yp; k1=yc/xc,k2=yc/(xc-xb),b2=yc*xb/(xb-xc); y1=xp*k1,y2=k2*xp+b2; if(yp<y1&&yp<y2)cout<<"yes"; else cout<<"no"; return 0; }
D-文稿修订
思路:只判断长度为4的单词
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=5e6+10,M=998244353; char s[N]; int n,f[N]; int main(){ cin.tie(0),cout.tie(0); s[0]=' '; int ans=0; while((s[++n]=::getchar())!='#'){} for(int i=1;i<n-3;++i){ if((s[i-1]==' '||s[i-1]=='\n')&&(s[i+4]==' '||s[i+4]=='\n')&&(s[i]=='n'||s[i]=='N')){ if((s[i+1]=='E'||s[i+1]=='e')&&(s[i+2]=='U'||s[i+2]=='u')&&(s[i+3]=='Q'||s[i+3]=='q')){ ans++; if(s[i]=='N'&&s[i+1]=='E'&&s[i+2]=='U'&&s[i+3]=='Q')ans--,f[i]=1; } } } cout<<ans<<'\n'; for(int i=1;i<n;++i){ if(f[i]==1)cout<<"WOW N"; else cout<<s[i]; } return 0; }
E-减肥计划
思路:n<=10,可用二进制枚举每一种情况;每种物品只有选和不选,可用dfs两种情况
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=15,M=998244353; int n,a,b,c,x[N],y[N],z[N],w[N]; int main() { ios::sync_with_stdio(false); cin.tie(0); cin>>n>>a>>b>>c; for(int i=0;i<n;++i)cin>>x[i]>>y[i]>>z[i]>>w[i]; int ans=0; for(int i=0;i<(1<<n);++i){ int xx=0,yy=0,zz=0,ww=0; for(int j=0;j<n;++j){ if(i>>j&1){ xx+=x[j],yy+=y[j],zz+=z[j],ww+=w[j]; } } if(xx<=a&&yy<=b&&zz<=c)ans=max(ans,ww); } cout<<ans; return 0; }
F-吃包子
思路:用前缀和求出范围内的肉包
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e6+10; int n,m,s[N],p[N]; vector<int>a; int main(){ cin>>n>>m; int ss=0; for(int i=0;i<n;++i){ cin>>s[i]; if(s[i]==1)ss++; p[i]=ss; if(s[i]==0)a.push_back(p[i]); } int res=0; if(a.size()<=m)cout<<p[n-1]; else{ for(int i=0;i<a.size()-m+1;++i){ if(i==0){ res=max(res,a[i+m]); } else if(i+m-1==a.size()-1){ res=max(res,ss-a[i-1]); } else{ res=max(res,a[i+m]-a[i-1]); } } cout<<res; } return 0; }
G-数字鉴定
思路:暴力解
#include <bits/stdc++.h> const int N = 1e6 + 7; int n, q, l, r,i; bool a[N]; bool is(int n) { if (a[n]) return false; else { for (i = 2 * n; i < N; i += n) { if (a[i]) return false; } return true; } } int main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); std::cin >> n >> q; while (n--) { std::cin >> l >> r; for (i = l; i <= r; i++) a[i] = true; } while (q--) { int x; std::cin >> x; std::cout << (is(x) ? "YES\n" : "NO\n"); } return 0; }
H-线性变换
思路:p的值是循环的,求出其循环范围即可求出x
#include<bits/stdc++.h> #define LL long long using namespace std; const int N=1e6+10; LL n,p,k,b,t,x,a[N],vis[N],sum[N]; int main(){ cin>>n>>p>>k>>b>>t; for(int i=0;i<n;i++)cin>>a[i]; for(LL i=1;i<=t;i++){ x+=a[p]; if(vis[p]){ LL len=i-vis[p]; LL d=x-sum[p]; LL tmp=(t-i)/len; LL r=(t-i)%len; x+=d*tmp; for(LL j=1;j<=r;j++)p=(k*p+b)%n,x+=a[p]; break; } sum[p]=x; vis[p]=i; p=(p*k+b)%n; } cout<<x<<endl; return 0; }
I-试题排版
思路:dp求完全背包方案数
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e6+10,M=998244353; int n, m; ll f[5100]; int main() { ios::sync_with_stdio(false); cin.tie(0); cin >> n; f[0] = 1; for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { if (j < i) continue; f[j] = (f[j] + f[j - i]) % M; } } cout << f[n] << "\n"; return 0; }
J-QQ群
思路:环的入读大于等于1,求出非环的最长路径,加上环的长度
#include <bits/stdc++.h> #define ll long long using namespace std; const int N = 1e4 + 5, M = 1e9 + 7; int n; queue<int> q; bool st[N]; int main() { cin.tie(0), cout.tie(0); cin>>n; vector<int> g[n+1],d(n+1),ru(n+1); int a; for(int i=1;i<=n;++i){ cin>>a; g[i].push_back(a); ru[a]++; } for(int i=0;i<=n;++i){ if(ru[i]==0){ q.push(i); d[i]=1,st[i]=true; } } int ans=0; while(!q.empty()){ int t=q.front(); q.pop(); for(auto x:g[t]){ d[x]=max(d[x],d[t]+1); if(--ru[x]==0){ q.push(x); st[x]=true; } } } for(int i=0;i<=n;++i)if(!st[i])ans++; int res=0; for(int i=0;i<=n;++i)res=max(res,d[i]); ans+=res; cout<<ans; return 0; }
M-粉色头发的可爱女孩
思路:种类有20种,用二进制代表每种可能,更新包含某种可能的可能的最大值
#include <bits/stdc++.h> #define ll long long using namespace std; const int N = 1<<22, M = 1e9 + 7; int n,k,q; pair<ll,ll> a[N]; int main() { cin.tie(0), cout.tie(0); cin>>n>>k; for(int i=1;i<=n;++i){ ll aa,m,t=0,x; cin>>aa>>m; for(int j=1;j<=m;++j){ cin>>x; t|=(1<<x-1); } if(aa>a[t].first){ a[t].second=i,a[t].first=aa; } } for(int i=1<<k;i>=0;--i){ for(int j=0;j<k;++j){ int t=i|(1<<j); if(a[t].first>a[i].first){ a[i].first=a[t].first,a[i].second=a[t].second; } } } cin>>q; while(q--){ int m,t=0,x; cin>>m; while(m--){ cin>>x; t|=(1<<x-1); } if(a[t].first)cout<<a[t].second<<'\n'; else cout<<"OMG!\n"; } return 0; }