我想想啊,这一场我才从发烧中爬起来打,勉勉强强做了一题,然后后面的全是构造,最后无奈下班。
脑袋有些晕,复杂一点的代码都不想写,实在是太痛苦了。
这一场掉74分。可能确实是不太行了,越打越菜。
A题
很简单一道题,样例里也给了解法,只要有a+b个,就可以保证后手赢。
B题
是构造,打表了,当时觉得万能解是可以质数在两边,非质数放中间,1在最中间,按从小到大左右发布,但是脑子烧坏了,写不出来,赛后补的。
题解的意思大概是,n<3时可单独处理,n>=3时,只要首个元素是2,末尾元素是3,中间元素是1就都是最优!
这个最优性证明是这样:
如何一个素性队列必定包含1,1放在最中间,即(n+1)/2的位置,因此如果n+1是素数,那么数组素性最大值应该是为(n+1)/2的平方,否则就是该基础减1即可。
所以代码大概长这个样就行:
void solve() { int n; cin>>n; if(n<3) { for(int i=1;i<=n;i++) cout<<i<<" "; cout<<"\n"; return; } a[n]=3,a[(n+1)/2]=1,a[1]=2; int x=n; for(int i=1;i<=n;i++) if(a[i]==0) a[i]=x--; for(int i=1;i<=n;i++) cout<<a[i]<<" ",a[i]=0; cout<<endl; }
很简单的问题,别想复杂了。
C题
这里首先要确定一点,每次融合对队列的影响是这样的,如果是在中间发生:消失一个,两个合一个,总量-2;在边缘发生:总量-1;
那么无论怎样,边缘处理可以直接损失掉小于0的所有结果,除非所有元素均小于0,否则我们得到的结果一定要大于0.
之后考虑两个大于0的数合并,首先,距离为奇数的两个元素肯定合并不了,也就是说,奇数合奇数的,偶数合偶数的,那我们就把这个序列分割开了.
ok,现在只要找两个序列里的最大值,再比较即可.贪心来说,最优策略肯定是负数不要正数全拿,记得开longlong,这个题也就这样了.
我的代码是这样的:
void solve() { int n; scanf("%d",&n); ll ans1=-1e9,ans2=-1e9; for(int i=1;i<=n;i++) { scanf("%lld",&a[i]); ans1=max(ans1,a[i]); ans2=max(ans2,a[i]); } if(ans1<0) { cout<<ans1<<endl; return; } ans1=ans2=0; for(int i=1;i<=n;i++) { if(i%2==1) { dp[i]=max(0ll,ans1)+a[i]; ans1=max(dp[i],ans1); } else { dp[i]=max(0ll,ans2)+a[i]; ans2=max(dp[i],ans2); } //cout<<dp[i]<<" "; }//cout<<endl; cout<<max(ans1,ans2)<<endl; }
D题
这一题我一看就知道应该与n的所有因数有关,其实还可以推到质因数.那么只要找到26以内的最小的非n的因数的质数k即可.
正确性是可以确定的,因为26以内前8个质数的积就已经大于n的范围了,所以该思路肯定正确.
然后只要重复k个不同字母到长度n即可.
void solve() { int n,ans; cin>>n; ans=n; for(int i=2;i<=n/2;i++) { if(n%i==0) a[i]=1; } for(int i=2;i<n;i++) { if(a[i]==0) { ans=i; break; } } int x=0; for(int i=1;i<=n;i++) { printf("%c",'a'+x); x=(x+1)%ans; a[i]=0; } cout<<endl; }