Codeforces 916 div3 A-F

[复制链接]
发表于 2026-2-19 19:45:49 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
A

题意分析:
看思考每个题的时间是否大于即是办理该题须要的时间,假如是,则能办理该题,否则不能,直接摆列计数即可
C++代码:
  1. #include<iostream>
  2. using namespace std;
  3. int main(){
  4.         int t,n;
  5.         cin>>t;
  6.         while(t--){
  7.                 cin>>n;
  8.                 string s;
  9.                 cin>>s;
  10.                 int cnt[26]={0};
  11.                 for(int i=0;i<s.size();i++){
  12.                         cnt[s[i]-'A']++;//思考A题的时间加一
  13.                 }
  14.                 int res=0;
  15.                 for(int i=0;i<26;i++){
  16.                         if(cnt[i]>=i+1)res++;//思考时间大于等于需要的时间
  17.                 }
  18.                 cout<<res<<endl;
  19.         }
  20.         return 0;
  21. }
复制代码
B

题意分析:
一开始先让数组按照n~1的序次分列,然后将前k+1个数从小到大排序即可
C++代码:
  1. #include<iostream>
  2. #include<algorithm>
  3. using namespace std;
  4. const int N=55;
  5. int a[N];
  6. bool cmp(int a,int b){
  7.         return a>b;
  8. }
  9. int main(){
  10.         int t;
  11.         cin>>t;
  12.         while(t--){
  13.                 int n,k;
  14.                 cin>>n>>k;
  15.                 for(int i=1,j=n;i<=n;i++,j--)a[i]=j;//先将所有数倒序
  16.                 sort(a+1,a+k+2);//把前k+1排成正序,就有了k次兴奋次数啦
  17.                 for(int i=1;i<=n;i++)cout<<a[i]<<" ";
  18.                 cout<<endl;
  19.         }
  20.         return 0;
  21. }
复制代码
C

题意分析:
 要求完成不高出k个任务可得到的最大的履历值
由于b数组中的元素都大于1,以是我们肯定会取到k个任务
假设i表现我们完成的任务停止到第i个,即i反面的任务都没做
此时可得到的最大履历值为a[1]+a[2]+...+a+(k-i)*(b[1~i]中的最大值)
以是要先预处理惩罚a的前缀和和b的前缀最大值
然后我们只需摆列每个任务作为分界点即可
C++代码:
  1. #include<iostream>
  2. using namespace std;
  3. const int N=200010;
  4. int a[N],b[N],maxx[N];
  5. int n,k;
  6. void solve(){
  7.         cin>>n>>k;
  8.         for(int i=1;i<=n;i++)maxx[i]=0;
  9.         for(int i=1;i<=n;i++)cin>>a[i],a[i]+=a[i-1];//a变成其前缀和
  10.     //maxx[i]含义:b[1~i]中最大的一个数
  11.         for(int i=1;i<=n;i++)cin>>b[i],maxx[i]=max(maxx[i-1],b[i]);
  12.         int ans=0;
  13.     //从前往后枚举解决的问题截止到第几个
  14.         for(int i=1;i<=min(n,k);i++){
  15.                 int sum=a[i]+(k-i)*maxx[i];//一共解决到第i个,剩下的k-i个直接用b[1~i]中最大的一个
  16.                 ans=max(ans,sum);//更新ans
  17.         }
  18.         cout<<ans<<endl;
  19. }
  20. int main(){
  21.     ios::sync_with_stdio(false);
  22.     cin.tie(0);
  23.     cout.tie(0);
  24.         int t;
  25.         cin>>t;
  26.         while(t--){
  27.                 solve();
  28.         }
  29.         return 0;
  30. }
复制代码
D 

题意分析:
先找出每种活动人数最多的三天,即找出每一行中最大的三个数
显然,最优解肯定是从这些数中每一行取一个,条件是这三个数不能在同一列,以是在存储最大的三个数时还要存一下坐标
C++代码:
  1. #include<iostream>
  2. #include<cstring>
  3. #define x first
  4. #define y second
  5. using namespace std;
  6. const int N=100010;
  7. typedef pair<int,int> PII;
  8. int a[4][N];
  9. int g[4][4];//存储每一行中最大的三个数
  10. PII s[4][4];//存储每一行中最大的三个数的坐标
  11. int n;
  12. void solve(){
  13.         cin>>n;
  14.         memset(g,0,sizeof g);
  15.         for(int i=1;i<=3;i++){
  16.                 int &d1=g[i][1],&d2=g[i][2],&d3=g[i][3];//存储每一行的最大值、次大值、第三大值
  17.                 PII &s1=s[i][1],&s2=s[i][2],&s3=s[i][3];//三个数的坐标
  18.                 for(int j=1;j<=n;j++){
  19.                         cin>>a[i][j];
  20.                         if(a[i][j]>=d1){
  21.                                 d3=d2,d2=d1,d1=a[i][j];
  22.                                 s3=s2,s2=s1,s1={i,j};
  23.                         }else if(a[i][j]>=d2){
  24.                                 d3=d2,d2=a[i][j];
  25.                                 s3=s2,s2={i,j};
  26.                         }else if(a[i][j]>d3){
  27.                                 d3=a[i][j];
  28.                                 s3={i,j};
  29.                         }
  30.                 }
  31.         }
  32.         //每一行的最大的三个及其下标已经找出来了
  33.         int ans=0;
  34.         for(int i=1;i<=3;i++)//第一行
  35.                 for(int j=1;j<=3;j++)//第二行
  36.                         for(int k=1;k<=3;k++){//第三行
  37.                                 PII s1=s[1][i],s2=s[2][j],s3=s[3][k];
  38.                                 if(s1.y!=s2.y&&s1.y!=s3.y&&s2.y!=s3.y)//它们不在同一列
  39.                                         ans=max(ans,g[1][i]+g[2][j]+g[3][k]);
  40.                         }
  41.         cout<<ans<<endl;
  42. }
  43. int main(){
  44.         ios::sync_with_stdio(false);
  45.         cin.tie(0);
  46.         cout.tie(0);
  47.         int t;
  48.         cin>>t;
  49.         while(t--){
  50.                 solve();
  51.         }
  52.         return 0;
  53. }
复制代码
E1 和 E2

题意分析:
假如一共有n种颜色,则利用n次肯定会竣事游戏,由于每次利用肯定会有至少一方该颜色的弹珠数变为0
Alice想赢(分数差值尽大概大)
Bob想赢(分数差值尽大概小)
对于颜色为i的弹珠
1、Alice举行利用,则对答案的贡献为a-1
2、Bob举行利用,则对答案的贡献为-(b-1)
二者的差值为(a-1)+(b-1)
以是:
Alice选i,答案差值增长了a-1+b-1
Bob选i,答案差值淘汰了a-1+b-1
以是每次不管谁利用时,挑a-1+b-1的最大值即可
C++代码:
  1. #include<iostream>
  2. #include<queue>
  3. using namespace std;
  4. typedef pair<int,int> PII;
  5. typedef long long LL;
  6. const int N=200010;
  7. int a[N],b[N];
  8. int n;
  9. void solve(){
  10.         cin>>n;
  11.         for(int i=1;i<=n;i++)cin>>a[i];
  12.         for(int i=1;i<=n;i++)cin>>b[i];
  13.         priority_queue<PII> q;//大根堆
  14.         for(int i=1;i<=n;i++)q.push({(a[i]-1)+(b[i]-1),i});
  15.         LL ans=0;
  16.         for(int i=1;i<=n;i++){
  17.                 PII t=q.top();
  18.                 q.pop();
  19.                 int id=t.second;
  20.                 if(i&1)ans+=a[id]-1;//Alice操作,答案加上a[id]-1
  21.                 else ans-=b[id]-1;//Bob操作,答案加上b[id]-1
  22.         }
  23.         cout<<ans<<endl;
  24. }
  25. int main(){
  26.         ios::sync_with_stdio(false);
  27.         cin.tie(0);
  28.         cout.tie(0);
  29.         int t;
  30.         cin>>t;
  31.         while(t--){
  32.                 solve();
  33.         }
  34.         return 0;
  35. }
复制代码
F 

题意分析:
对于某一棵子树,只要两个点不在一根链上,就可以组队
假设当前子树的根节点为u
maxn记载最大子树中的节点数量
sum记载全部子树的节点数量和
match记载最大子树中的最大匹配数(两人一匹配)
有两种情况:
1、maxn-match*2<=sum-maxn,则最大匹配数为sum/2
2、maxn-match*2>sum-maxn,则最大匹配数为match+sum-maxn
以是直接dfs搜以每个节点为根的子树的情况即可
C++代码:
  1. #include<iostream>
  2. #include<vector>
  3. using namespace std;
  4. typedef long long LL;
  5. const int N=200010;
  6. int h[N],e[N],ne[N],idx;
  7. int size1[N],dp[N];//子树大小,最大子树能组成的队伍数
  8. int n;
  9. void add(int a,int b){
  10.         e[idx]=b,ne[idx]=h[a],h[a]=idx++;
  11. }
  12. void dfs(int u){
  13.         size1[u]=1;//以u为根的子树中的节点数一开始只有自己
  14.         dp[u]=0;//最开始能配对的数量为0
  15.         int maxn=0,match=0,sum=0,cnt=0;
  16.         //sum表示所有子树节点之和,maxn表示最大子树中节点数量,match表示最大子树中已经匹配的队伍数
  17.         //cnt用于记录节点u有几个子节点
  18.         for(int i=h[u];i!=-1;i=ne[i]){
  19.                 int j=e[i];
  20.                 cnt++;
  21.                 dfs(j);//这里不用判断j是否被搜过是因为这是一个有向图无环树,所以不可能往回搜
  22.                 size1[u]+=size1[j];
  23.                 dp[u]=max(dp[u],dp[j]);
  24.                 if(maxn<size1[j]){
  25.                         maxn=size1[j];
  26.                         match=dp[j];
  27.                 }
  28.                 sum+=size1[j];
  29.         }
  30.         if(cnt==1)return;//只有一棵子树
  31.         if(sum-maxn>=maxn-match*2)dp[u]=sum/2;
  32.         else dp[u]=sum-maxn+match;
  33. }
  34. void solve(){
  35.     cin>>n;
  36.     for(int i=1;i<=n;i++)h[i]=-1;//初始化h数组
  37.     idx=0;
  38.     for(int i=2;i<=n;i++){
  39.             int x;
  40.             cin>>x;
  41.             add(x,i);
  42.         }
  43.     dfs(1);
  44.     cout<<dp[1]<<endl;
  45. }
  46. int main(){
  47.     int T;
  48.     cin>>T;
  49.     while(T--){
  50.         solve();
  51.     }
  52.     return 0;
  53. }
复制代码


回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表