本来准备做一整套的……但太阳这么好为什么不出去溜溜弯呢。
A. Equidistant Letters
题意:给出一串字母,每种字母要求间隔相等,输出一种可能的结论。
解:间隔相等,那连续输出就好了。
代码:
#include<bits/stdc++.h> using namespace std; #define ll long long #define maxx 2005 #define eps 0.00000001 #define inf 0x3f //#define int long long char a[maxx]; signed main() { int T; scanf("%d",&T); while(T--){ int num[30]={0}; scanf("%s",a); for(int i=0;i<strlen(a);i++) num[a[i]-'a']++; for(int i=0;i<26;i++){ for(int j=0;j<num[i];j++) printf("%c",i+'a'); } printf("\n"); } return 0; }
B. Minor Reduction
题意:给出一串很长的数,从中挑出两个数把它们换成它们的和。执行一次这样的操作,求获得新串的最大值。
解:可以证明将两个数替换为它们的和总会变小。那么我们希望变小的在最低位,同时它加完还是个两位数,不然少一位会变得更小。从低位向高位遍历,碰到相加大于等于十替换。如果不存在这样的两个数,那么将开头两个数合起来,虽然少了一位,但最高位最大。
代码:
#include<bits/stdc++.h> using namespace std; #define ll long long #define maxx 200005 #define eps 0.00000001 #define inf 0x3f //#define int long long char s[maxx]; signed main() { int T; scanf("%d",&T); while(T--){ scanf("%s",s); int flag=0; for(int i=strlen(s);i>0;i--){ int t=s[i]-'0'+s[i-1]-'0'; if(t>9){ s[i]=t%10+'0'; s[i-1]=t/10+'0'; flag=1; break; } } if(!flag){ s[1]=s[0]-'0'+s[1]; printf("%s\n",s+1); } else printf("%s\n",s); } return 0; }
C. Monsters And Spells
题意:打怪物。第i个怪物只在 ki 时刻出现,血量为 hi 。每个时刻初始伤害为1,如果连续蓄力a个时刻,伤害可以累积到a。求每个时刻能打出伤害的最小和。
解:如果第 ki 时刻要打血量为 hi 的怪,那他在 ki - hi + 1时刻就要开始蓄力。于是这道题转换成了讨厌的区间合并问题。抄板子吧。
代码:
#include<bits/stdc++.h> using namespace std; #define ll long long #define maxx 105 #define eps 0.00000001 #define inf 0x3f //#define int long long int n; int k[maxx]={0},h[maxx]={0}; int s; ll f(ll x){ return (1+x)*x/2; } signed main() { int T; scanf("%d",&T); while(T--){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&k[i]); for(int i=1;i<=n;i++) scanf("%d",&h[i]); vector<pair<ll,ll> > v; for(int i=1;i<=n;i++) { s = k[i] - h[i] + 1; v.push_back(make_pair(s,k[i])); } sort(v.begin(),v.end()); ll st = -1, ed = -1,ans=0; for(auto i : v){ if(ed < i.first){ if(st != -1) ans+=f(ed-st+1); st = i.first, ed = i.second; } else ed = max(ed, i.second); //有交集 } ans+=f(ed-st+1); printf("%lld\n",ans); } return 0; }
D. Martial Arts Tournament
题意:要将n个选手分为三个重量级,同时希望每个等级的人数刚好能产生一名冠军,也就是2的幂。分级标准是选两个数x、y,分为 [...,x), [x,y), [y,...)三组。求至少添加多少人,每组的人数刚好为2的幂。
解:枚举x和y显然会炸,那就枚举最后的人数为多少。假设最终第一组有 2a 人,第三组有 2b人,第二组有 n - 2a - 2b 人,再分别算出距离目标差多少,暴力求最小值即可。中间用前缀和以及二分优化一下,每次都想吐槽没找到为什么不返回-1。。。虽然和这题没关系。
代码:
#include<bits/stdc++.h> using namespace std; #define ll long long #define maxx 200005 #define eps 0.00000001 #define inf 0x7fffffff //#define int long long int n; int a[maxx]; int b[50]; ll pre[maxx]={0},suf[maxx]={0}; int cnt1,cnt2; ll f(int x){ int t= lower_bound(b,b+30,x)-b; return b[t]-x; } ll check(int x,int y){ int a1= upper_bound(pre+1,pre+1+cnt1,x)-pre-1; int a2= upper_bound(suf+1,suf+1+cnt2,y)-suf-1; int num1=pre[a1],num2=suf[a2]; if(a1==0) num1=0; if(a2==0) num2=0; int num3=n-num1-num2; ll res=f(num1)+f(num2)+f(num3); return res; } signed main() { int T; scanf("%d",&T); b[0]=1; for(int i=1;i<=30;i++) b[i]=(b[i-1]<<1); while(T--){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); sort(a+1,a+1+n); cnt1=0; ll temp=1; for(int i=2;i<=n;i++){ if(a[i]==a[i-1]) temp++; if(a[i]!=a[i-1]||i==n){ cnt1++; pre[cnt1]=pre[cnt1-1]+temp; temp=1; } } cnt2=0,temp=1; for(int i=n-1;i>=0;i--){ if(a[i]==a[i+1]) temp++; if(a[i]!=a[i+1]||i==0){ cnt2++; suf[cnt2]=suf[cnt2-1]+temp; temp=1; } } ll ans=inf; for(int i=0;i<=18;i++){ for(int j=0;j<=18;j++) ans=min(ans, check(b[i],b[j])); } printf("%lld\n",ans); } return 0; }