A. Problemsolving Log
题目大意
给定一个字符串,统计其中出现次数大于其在字母表位次的字母个数,例如A需要出现1次,Z需要出现26次
题解
开map记录每个字母出现多少次,满足条件的输出,阅读能力太差了,签到题写半天
代码
#include<iostream>
#include<map>
#include<cstring>
using namespace std;
string s;
map<char,int>mp;
int main()
{
int t;
cin>>t;
while(t--)
{
mp.clear();
int n;
cin>>n>>s;
int res=0;
for(int i=0;i<s.size();i++)
{
mp[s[i]]++;
}
for(char c='A';c<='Z';c++)
{
if(mp[c]>=c-'A'+1) res++;
}
cout<<res<<endl;
//cout<<'A'-64;
}
return 0;
}
B. Preparing for the Contest
题目大意
给定从1-n,n个数字,输出时要求其中有k个数字比前一个数大
题解
此题为构造题,我们找出通解即可,不难发现n个升序的数,可提供n-1个比前一个数大的数
那么我们需要k+1个升序的数,n-(k+1)个降序的数
代码
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
//#include<queue>
//#include<map>
//#include<vector>
//#include<set>
//#include<deque>
//#include<bitset>
//#include<functional>
using namespace std;
#define long long ll;
typedef pair<int,int>PII;
int main()
{
int t;
cin>>t;
while(t--)
{
int n,k;
cin>>n>>k;
for(int i=1,j=n;i<=n-k-1;i++) cout<<j--<<" ";
for(int i=1,j=1;i<=k+1;i++) cout<<j++<<" ";
cout<<endl;
}
return 0;
}
C. Quests
题目大意
一共有n个任务,最多可以完成k个,每个任务有首次完成奖励和重复完成奖励,每个任务可以重复完成,只有做完前一天的任务才能做下一天的任务,求可获得的最大的奖励
题解
用贪心的思想,对于做到第i个任务可以获得的最大奖励为:1-i个任务的首次完成奖励(这里可以用前缀和计算)+(k-i)*1-i个任务中重复完成奖励最大的任务奖励
然后我们枚举所有的可能做到的任务,取奖励最大值即可
代码
#include<iostream>
#include<algorithm>
using namespace std;
const int N=2e5+10;
typedef long long ll;
ll a[N],b[N];
ll s[N];
ll f[N];//表示只解锁第i个任务获得的最大经验值
int main()
{
int t;
cin>>t;
while(t--)
{
ll n,k;
cin>>n>>k;
for(ll i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
s[i]=s[i-1]+a[i];//1-i个任务的首次完成奖励之和
}
for(ll i=1;i<=n;i++) scanf("%lld",&b[i]);
ll maxn=-1e9;
for(ll i=1;i<=n;i++)
{
maxn=max(maxn,b[i]);
f[i]=s[i]+maxn*(k-i);
}
ll ans=-1e9;//这里枚举能做的任务数一定不超过任务总数与可以完成的任务数
for(ll i=1;i<=k && i<=n;i++) ans=max(ans,f[i]);
cout<<ans<<endl;
}
return 0;
}
D. Three Activities
题目大意
给定三个数组,求三个下标不同的数之和
题解
其实没有必要枚举全部元素,不难发现符合条件的三个数一定在每个数组前三大的数中产生,所以我们将三个数组降序排序,并枚举每个数组前三大的数,取和最大且下标不同的即可。这里使用了结构体存储下标
代码
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int N=2e5+10;
struct edge{
int v,ii;//值,下标
bool operator < (edge const &t) const//重载大于号,降序排
{
return v>t.v;
}
}a[N],b[N],c[N];
int main()
{
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i].v,a[i].ii=i;
for(int i=1;i<=n;i++) cin>>b[i].v,b[i].ii=i;
for(int i=1;i<=n;i++) cin>>c[i].v,c[i].ii=i;
sort(a+1,a+n+1);
sort(b+1,b+n+1);
sort(c+1,c+n+1);
int maxn=0;
for(int i=1;i<=3;i++)
{
for(int j=1;j<=3;j++)
{
for(int z=1;z<=3;z++)
{
if(a[i].ii==b[j].ii || b[j].ii==c[z].ii || a[i].ii==c[z].ii) continue;
int ans=a[i].v+b[j].v+c[z].v;
maxn=max(maxn,ans);
}
}
}
cout<<maxn<<endl;
}
return 0;
}
E2. Game with Marbles (Hard Version)
E1为E2数据弱化版
题目大意
a和b都有n种颜色不同的弹珠,每人轮流行动,每次行动可以选择一种颜色,将对方该种颜色的弹珠清0,自己该种颜色的弹珠-1,前提是两人都至少有一颗该种颜色的弹珠。当两人都无法进行操作,即两人没有数量都大于1的相同颜色弹珠时,游戏结束。最后的分数a的弹珠数量减b的弹珠数量。a想要将分数最大化,b想要将分数最小化,假设两人都聪明绝顶,每次行动一定是对自己最优的,求最终分数。
题解
我们假设一组数据
a: x u
b: y v
则当a选择第一种颜色时,a可获得分数为x-1,b可获得的分数为v-1,则最终分数为x-v
当a选择第二种颜色时,a可获得的分数为u-1,b可获得的分数为y-1,则最终分数为u-y
所以为了最大化分数,当x-v>u-y时a会选择操作第一种颜色的弹珠,当x-v小于u-y时,a会选择操作第二种颜色的弹珠。移项之后即x+y>u+v时会选择第一种颜色的弹珠,x+y<u+v时会选择第二种颜色的弹珠。所以我们发现两人每次选择的弹珠颜色,一定是两人拥有相同颜色弹珠的数目之和最大的弹珠颜色。
也就是说两人一定轮流操作弹珠数量之和最大的弹珠,那么我们可以计算出每种颜色弹珠的数量之和,并降序排序。模拟两人轮流取弹珠的过程,由于最终分数为a的弹珠数减b的弹珠数,所以a对最总分数的贡献为加上该种颜色弹珠可获得的·分数,而b对最终分数的共享为减去该种颜色弹珠可获得的分数。而每人对该种颜色弹珠可获得的分数即自己拥有的该种颜色弹珠的数量减一。
代码
// Problem: E1. Game with Marbles (Easy Version)
// Contest: Codeforces - Codeforces Round 916 (Div. 3)
// URL: https://codeforces.com/contest/1914/problem/E1
// Memory Limit: 256 MB
// Time Limit: 3500 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
//#include<queue>
//#include<map>
//#include<vector>
//#include<set>
//#include<deque>
//#include<bitset>
//#include<functional>
#define ll long long
using namespace std;
typedef pair<int,int>PII;
const int N=2e6+10;
struct edge{
int a,b;//a和b分别拥有该种颜色弹珠的数量
int sum;//该种颜色弹珠数量之和
bool operator < (edge const &t) const //重载大于号,降序排
{
return sum>t.sum;
}
};
edge f[N];
int main()
{
int t;
cin>>t;
while(t--)
{
ll res=0;//答案
int n;
cin>>n;
for(int i=1;i<=n;i++) cin>>f[i].a;
for(int i=1;i<=n;i++) cin>>f[i].b,f[i].sum=f[i].a+f[i].b;
sort(f+1,f+n+1);
for(int i=1;i<=n;i++)
{
if(i%2) res+=f[i].a-1;//a的回合获得的分数为a弹珠数量-1
else res-=f[i].b-1;//b的回合获得的分数为b弹珠数量-1
}
cout<<res<<endl;
}
return 0;
}
谨记大佬赛后写题解的教诲,遂写下第一篇题解,希望自己能坚持下去。