wa得老惨了qwq,本来还以为只能一题,太惨了太惨了
A. And Then There Were K
给你一个n,求最大的k使得:
思路:求n二进制最高位对应的数-1
int n; void solve() { sd(n); int nn=n,val=1; while(nn) { val<<=1; nn>>=1; } val>>=1; pd(val-1); }
B1. Palindrome Game (easy version)
给你一个01回文串
想要将这个字符串变为全1
两个操作:
1、将其中一个0变为1,花费1
2、当该字符串不是回文串且上一个操作不是2则可将该字符串反转,花费0
ALICE先手
最后花费最少的人获胜
思路:因为当前是回文,所以ALICE第一次必花费
cnt代表0的个数,当cnt是奇数代表中间是0
cnt为1时只能只有ALICE操作
当cnt为2时的操作为(1)ALICE花费1(2)BOB反转(3)ALICE花费1
当cnt为偶数且cnt>2时,BOB每次选择ALICE对应的位置的0变为1,直到cnt为2
当cnt为奇数时,ALICE选择中间的0变为1,然后风水轮流转,cnt变为偶数,自行代入上面的情况hhh
当cnt=1时花费为1:0
当cnt为奇数时花费差1
当cnt为偶数时花费差2
int n; char s[maxn]; void solve() { sd(n); sc(s+1); int cnt=0; rep(i,1,n)if(s[i]=='0')cnt++; if(cnt==1)puts("BOB"); else if(cnt&1)puts("ALICE"); else puts("BOB"); }
B2. Palindrome Game (hard version)
题意同上,只是原来的串不一定是回文串
int n,cnt,cnt1; char s[maxn]; void solve() { sd(n); sc(s+1); cnt=cnt1=0; rep(i,1,n) { if(s[i]=='1')continue; if(s[i]==s[n-i+1])cnt++; else cnt1++; } if(cnt1>=2||!cnt) { puts("ALICE"); return; } if(cnt1==1) { if(cnt==1)puts("DRAW"); else puts("ALICE"); return; } if(cnt==1)puts("BOB"); else if(cnt&1)puts("ALICE"); else puts("BOB"); }
cnt为该位置为0且对应位置为0的个数
cnt1为该位置为0且对应位置为1的个数
当cnt为0时,按上一题解法
因为当cnt1>=3时,ALICE先每次都选择反转,BOB只能选择cnt1对应位置的0变为1,直到变为回文串,这时比分已经是0:cnt1了,BOB不可能反败为胜
当cnt1=2时,如果cnt为奇数,等到变为回文串时,ALICE是先手,具体同上一题;如果cnt为偶数,那么ALICE在第二次操作时选择将另一个cnt1的0变为1,然后变成的情况可参考上一题
当cnt1=1时,如果cnt为奇数,同上;否则ALICE第一步直接选择将这个0变为1,然后就变成的情况可参考上一题
C. Sequence Pair Weight
给一个长度为n的数组,区间[l,r]的值为在这区间内,ai=aj的对数
让你求对于所有的子区间的值和。
害,这题有点难讲啊,毕竟我也是混过去的(不会吧不会吧,不会有人要来hack我吧),暂时先只放代码吧
int n,a[maxn]; int l[maxn],pre[maxn],cnt[maxn]; ll ans,sum[maxn]; void solve() { sd(n);ans=0; rep(i,1,n)sd(a[i]),l[i]=a[i]; sort(l+1,l+1+n); int m=unique(l+1,l+1+n)-l-1; rep(i,1,m)pre[i]=0,sum[i]=0; ll sum1=0; rep(i,1,n) { int k=lower_bound(l+1,l+1+m,a[i])-l; ans+=sum1; sum[k]+=pre[k]; ans+=sum[k]; pre[k]=i; sum1+=sum[k]; } plld(ans); }