马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
A
题意分析:
看思考每个题的时间是否大于即是办理该题须要的时间,假如是,则能办理该题,否则不能,直接摆列计数即可
C++代码:- #include<iostream>
- using namespace std;
- int main(){
- int t,n;
- cin>>t;
- while(t--){
- cin>>n;
- string s;
- cin>>s;
- int cnt[26]={0};
- for(int i=0;i<s.size();i++){
- cnt[s[i]-'A']++;//思考A题的时间加一
- }
- int res=0;
- for(int i=0;i<26;i++){
- if(cnt[i]>=i+1)res++;//思考时间大于等于需要的时间
- }
- cout<<res<<endl;
- }
- return 0;
- }
复制代码 B
题意分析:
一开始先让数组按照n~1的序次分列,然后将前k+1个数从小到大排序即可
C++代码:- #include<iostream>
- #include<algorithm>
- using namespace std;
- const int N=55;
- int a[N];
- bool cmp(int a,int b){
- return a>b;
- }
- int main(){
- int t;
- cin>>t;
- while(t--){
- int n,k;
- cin>>n>>k;
- for(int i=1,j=n;i<=n;i++,j--)a[i]=j;//先将所有数倒序
- sort(a+1,a+k+2);//把前k+1排成正序,就有了k次兴奋次数啦
- for(int i=1;i<=n;i++)cout<<a[i]<<" ";
- cout<<endl;
- }
- return 0;
- }
复制代码 C
题意分析:
要求完成不高出k个任务可得到的最大的履历值
由于b数组中的元素都大于1,以是我们肯定会取到k个任务
假设i表现我们完成的任务停止到第i个,即i反面的任务都没做
此时可得到的最大履历值为a[1]+a[2]+...+a+(k-i)*(b[1~i]中的最大值)
以是要先预处理惩罚a的前缀和和b的前缀最大值
然后我们只需摆列每个任务作为分界点即可
C++代码:- #include<iostream>
- using namespace std;
- const int N=200010;
- int a[N],b[N],maxx[N];
- int n,k;
- void solve(){
- cin>>n>>k;
- for(int i=1;i<=n;i++)maxx[i]=0;
- for(int i=1;i<=n;i++)cin>>a[i],a[i]+=a[i-1];//a变成其前缀和
- //maxx[i]含义:b[1~i]中最大的一个数
- for(int i=1;i<=n;i++)cin>>b[i],maxx[i]=max(maxx[i-1],b[i]);
- int ans=0;
- //从前往后枚举解决的问题截止到第几个
- for(int i=1;i<=min(n,k);i++){
- int sum=a[i]+(k-i)*maxx[i];//一共解决到第i个,剩下的k-i个直接用b[1~i]中最大的一个
- ans=max(ans,sum);//更新ans
- }
- cout<<ans<<endl;
- }
- int main(){
- ios::sync_with_stdio(false);
- cin.tie(0);
- cout.tie(0);
- int t;
- cin>>t;
- while(t--){
- solve();
- }
- return 0;
- }
复制代码 D
题意分析:
先找出每种活动人数最多的三天,即找出每一行中最大的三个数
显然,最优解肯定是从这些数中每一行取一个,条件是这三个数不能在同一列,以是在存储最大的三个数时还要存一下坐标
C++代码:- #include<iostream>
- #include<cstring>
- #define x first
- #define y second
- using namespace std;
- const int N=100010;
- typedef pair<int,int> PII;
- int a[4][N];
- int g[4][4];//存储每一行中最大的三个数
- PII s[4][4];//存储每一行中最大的三个数的坐标
- int n;
- void solve(){
- cin>>n;
- memset(g,0,sizeof g);
- for(int i=1;i<=3;i++){
- int &d1=g[i][1],&d2=g[i][2],&d3=g[i][3];//存储每一行的最大值、次大值、第三大值
- PII &s1=s[i][1],&s2=s[i][2],&s3=s[i][3];//三个数的坐标
- for(int j=1;j<=n;j++){
- cin>>a[i][j];
- if(a[i][j]>=d1){
- d3=d2,d2=d1,d1=a[i][j];
- s3=s2,s2=s1,s1={i,j};
- }else if(a[i][j]>=d2){
- d3=d2,d2=a[i][j];
- s3=s2,s2={i,j};
- }else if(a[i][j]>d3){
- d3=a[i][j];
- s3={i,j};
- }
- }
- }
- //每一行的最大的三个及其下标已经找出来了
- int ans=0;
- for(int i=1;i<=3;i++)//第一行
- for(int j=1;j<=3;j++)//第二行
- for(int k=1;k<=3;k++){//第三行
- PII s1=s[1][i],s2=s[2][j],s3=s[3][k];
- if(s1.y!=s2.y&&s1.y!=s3.y&&s2.y!=s3.y)//它们不在同一列
- ans=max(ans,g[1][i]+g[2][j]+g[3][k]);
- }
- cout<<ans<<endl;
- }
- int main(){
- ios::sync_with_stdio(false);
- cin.tie(0);
- cout.tie(0);
- int t;
- cin>>t;
- while(t--){
- solve();
- }
- return 0;
- }
复制代码 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++代码:- #include<iostream>
- #include<queue>
- using namespace std;
- typedef pair<int,int> PII;
- typedef long long LL;
- const int N=200010;
- int a[N],b[N];
- int n;
- void solve(){
- cin>>n;
- for(int i=1;i<=n;i++)cin>>a[i];
- for(int i=1;i<=n;i++)cin>>b[i];
- priority_queue<PII> q;//大根堆
- for(int i=1;i<=n;i++)q.push({(a[i]-1)+(b[i]-1),i});
- LL ans=0;
- for(int i=1;i<=n;i++){
- PII t=q.top();
- q.pop();
- int id=t.second;
- if(i&1)ans+=a[id]-1;//Alice操作,答案加上a[id]-1
- else ans-=b[id]-1;//Bob操作,答案加上b[id]-1
- }
- cout<<ans<<endl;
- }
- int main(){
- ios::sync_with_stdio(false);
- cin.tie(0);
- cout.tie(0);
- int t;
- cin>>t;
- while(t--){
- solve();
- }
- return 0;
- }
复制代码 F
题意分析:
对于某一棵子树,只要两个点不在一根链上,就可以组队
假设当前子树的根节点为u
maxn记载最大子树中的节点数量
sum记载全部子树的节点数量和
match记载最大子树中的最大匹配数(两人一匹配)
有两种情况:
1、maxn-match*2<=sum-maxn,则最大匹配数为sum/2
2、maxn-match*2>sum-maxn,则最大匹配数为match+sum-maxn
以是直接dfs搜以每个节点为根的子树的情况即可
C++代码:- #include<iostream>
- #include<vector>
- using namespace std;
- typedef long long LL;
- const int N=200010;
- int h[N],e[N],ne[N],idx;
- int size1[N],dp[N];//子树大小,最大子树能组成的队伍数
- int n;
- void add(int a,int b){
- e[idx]=b,ne[idx]=h[a],h[a]=idx++;
- }
- void dfs(int u){
- size1[u]=1;//以u为根的子树中的节点数一开始只有自己
- dp[u]=0;//最开始能配对的数量为0
- int maxn=0,match=0,sum=0,cnt=0;
- //sum表示所有子树节点之和,maxn表示最大子树中节点数量,match表示最大子树中已经匹配的队伍数
- //cnt用于记录节点u有几个子节点
- for(int i=h[u];i!=-1;i=ne[i]){
- int j=e[i];
- cnt++;
- dfs(j);//这里不用判断j是否被搜过是因为这是一个有向图无环树,所以不可能往回搜
- size1[u]+=size1[j];
- dp[u]=max(dp[u],dp[j]);
- if(maxn<size1[j]){
- maxn=size1[j];
- match=dp[j];
- }
- sum+=size1[j];
- }
- if(cnt==1)return;//只有一棵子树
- if(sum-maxn>=maxn-match*2)dp[u]=sum/2;
- else dp[u]=sum-maxn+match;
- }
- void solve(){
- cin>>n;
- for(int i=1;i<=n;i++)h[i]=-1;//初始化h数组
- idx=0;
- for(int i=2;i<=n;i++){
- int x;
- cin>>x;
- add(x,i);
- }
- dfs(1);
- cout<<dp[1]<<endl;
- }
- int main(){
- int T;
- cin>>T;
- while(T--){
- solve();
- }
- return 0;
- }
复制代码
|