B. Special Numbers
题意: 给你n和k,进行幂运算,n为幂底数,将n的所有幂以及不同幂之和按顺序排列,找到第k个数。
如:n=3,k=4,序列为{1,3,4,9},表示30,31,30+31,32。
分析: 比赛的时候不会做,自己想的很复杂。
以下都是废话,直接从黑体字开始看。
以n=2,k=12为例。序列幂的指数排序如下:
0 个数为1
1 01 个数为2
2 02 12 012 个数为4
3 03 13 013 23 023 123 0123 个数为8
4 04 14 014 24 024 124 0124 34 034 134 0134 234 0234 1234 01234 个数为16
…
序列为:
1
2 3
4 5 6 7
8 9 10 12 11 13 14 15
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
…
第12个数为22+23=4+8=12
找规律发现每一行的个数为2的次方,所以我先根据k找到该数在第几行(为了和幂的次方对应,假设有第0行),int m=int(log(k)/log(2)),2m为该行数的个数。然后计算k为该行的第几个数,先计算sum=20+…+2m-1,然后int t=k-sum,t为m行的第几个数,本例m=3,t=12-7=5。
然后就卡住了。。。
分析了一大堆,觉得该用二进制操作。。。
以n=2,k=12为例,我们考虑12的二进制数1100,
发现结果恰好为1 * 23+1 * 22+0 * 21+0 * 20=8+4=12,从上面的列举也能发现指数的排序为23;
以n=3,k=4为例,4的二进制数为100,结果就为1 * 32+0 * 31+0 *3 0= 9。
怎么想到的?因为不论n取什么值,指数的排列是固定的,对应的k的位置也是固定的,从上面两个表中找对应关系,发现当n取2时,序列恰好是自然数排列,那么我们找k时,无论n取什么,一定都与n=2时的k在同一个位置,自然也就对应了指数的序列。比如:k=12,n=2时指数序列为2 3,也就是二进制中1100,1代表的数。
#includeusing namespace std; int mod=1e9+7; int main() { int t,n,k,ans,now; cin>>t; while(t--) { cin>>n>>k; ans=0,now=1; while(k) { if(k&1)//二进制取末尾 ans=(ans+now)%mod; now=1ll*now*n%mod;//1ll表示把int转换成long long型 k>>=1; } cout< C. Make Them Equal
题意:给你一个字符串s和字符c,每次操作可以选一个x(1<=x<=n),字符串不能整除x的位置上的字符替换成c,问操作几次可以使s的每一位全变成c。分析:一开始情况没考虑全面,想的是从字符串的第2位到第n-1位找,如果有一个字符不是c,x1就等于n,然后判断第n位,如果不是c,x2就等于n-1,一共两步;如果字符串第二位到第n-1位都等于c,此时,如果第一位或第n位不是c,x1直接等于n-1即可。要么一步要么两步。
但这样写两步的时候没有考虑到2~n-1中存在一个m,且n<2*m,当2到n-1中存在一位(非m)不等于c,只需一步,x1=m。举个例子,5 b,babaa,我一开始的结果是2 5 4,实际上应该是1 3。
赛后重新修改代码#includeusing namespace std; int main() { int t,n; cin>>t; char c,s[300010]; int cc[5]; while(t--) { cin>>n>>c>>(s+1); int sum=0,p=0; for(int i=n-1; i>=2; i--) { if(s[i]!=c) { sum++; cc[p++]=n; break; } } if(sum) { if(s[n]!=c) { sum++; cc[p++]=n-1; } } else { if(s[1]!=c||s[n]!=c) { sum++; cc[p++]=n-1; } } if(sum==2) { for(int i=round((n+1)*1.0/2);i<=n-1;i++) { if(s[i]==c) { sum=1; p=1; cc[0]=i; break; } } } cout<



