Codeforces Round #553 (Div. 2)
A. Maxim and Biology
题意:
给出一个串s,问最少需要多少步操作使得串s包含"ACTG"这个子串,输出最少操作次数;
题解:
枚举每个位置 i,求出将 i,i+1,i+2,i+3 变为 "ACTG" 所需的最少操作次数即可;
AC代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define INF 0x3f3f3f3f 4 #define ll long long 5 #define mem(a,b) memset(a,b,sizeof(a)) 6 7 int n; 8 char s[100]; 9 10 int Step(char x1,char x2)//求解x1变为x2所需的最少操作步骤 11 { 12 if(x1 <= x2) 13 return min(x2-x1,x1-'A'+'Z'-x2+1); 14 else 15 return min(x1-x2,'Z'-x1+x2-'A'+1); 16 } 17 //求解以index位置开始使得其连续的四个字符变为"ACTG"所需的最小操作步骤 18 int F(int index) 19 { 20 int ans=0; 21 ans += Step(s[index],'A'); 22 ans += Step(s[index+1],'C'); 23 ans += Step(s[index+2],'T'); 24 ans += Step(s[index+3],'G'); 25 return ans; 26 } 27 int Solve() 28 { 29 int ans=INF; 30 int len=strlen(s); 31 for(int i=0;i+4 <= len;++i) 32 ans=min(ans,F(i)); 33 return ans; 34 } 35 int main() 36 { 37 // freopen("C:\\Users\\hyacinthLJP\\Desktop\\in&&out\\contest","r",stdin); 38 while(~scanf("%d",&n)) 39 { 40 scanf("%s",s); 41 printf("%d\n",Solve()); 42 } 43 return 0; 44 }
B. Dima and a Bad XOR
题意:
给出一个 n*m 的矩阵a[][],每一行任选一个元素,判断选出的这 n 个元素的异或和是否大于0;
如果存在大于0的选法,输出 "TAK" ,并且输出每一行选择的元素的列标;
如果不存在,输出 "NIE";
题解:
令 ans = a[1][1]^a[2][1]^........^a[n][1];
①ans > 0 : 输出 n 个 1
②ans == 0 : 判断是否可以将a[1][1] 或 a[2][1] 或 ..... 或 a[n][1] 变成同一行的其他元素;
如果可以,输出 "TAK",并将任意一个a[ i ][1]变为同行中的其他元素;
反之,输出"NIE";
AC代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int n,m; 5 int a[600][600]; 6 int tmp[600]; 7 8 bool isSat()//判断是否存在去重后的元素个数 > 1 的行 9 { 10 for(int i=1;i <= n;++i) 11 { 12 /** 13 如果想要从tmp[1]位置作为起始位置,第一个参数为tmp+1 14 a[i]数组第一个位置的下标为a[i][1],所以第二个参数为a[i]+1 15 第三个参数不是指数组个数,而是指要复制的数据的总字节数长度 16 */ 17 memcpy(tmp+1,a[i]+1,m*sizeof(int));//将a[i]数组拷贝给tmp数组 18 sort(tmp+1,tmp+m+1); 19 int t=unique(tmp+1,tmp+m+1)-tmp;//去重 20 t--; 21 if(t > 1) 22 return true; 23 } 24 return false; 25 } 26 void Solve() 27 { 28 int ans=0; 29 for(int i=1;i <= n;++i) 30 ans ^= a[i][1]; 31 32 if(ans != 0 || ans == 0 && isSat()) 33 { 34 printf("TAK\n"); 35 bool flag=(ans != 0);//如果ans != 0,输出n个1 36 for(int i=1;i <= n;++i) 37 { 38 if(!flag) 39 { 40 for(int j=2;j <= m;++j) 41 if(a[i][j] != a[i][1]) 42 { 43 flag=true;//如果ans=0,找到第一个相异与a[i][1]的元素的列标即可 44 printf("%d ",j); 45 break;//记得break,不然,printf("%d ",j) 可能会调用多次 46 } 47 if(!flag) 48 printf("1 "); 49 } 50 else 51 printf("1 "); 52 } 53 printf("\n"); 54 } 55 else 56 printf("NIE\n"); 57 } 58 int main() 59 { 60 while(~scanf("%d%d",&n,&m)) 61 { 62 for(int i=1;i <= n;++i) 63 for(int j=1;j <= m;++j) 64 scanf("%d",a[i]+j); 65 Solve(); 66 } 67 return 0; 68 }
C. Problem for Nazar
题意:
给定奇数集和偶数集;
现构造一个数组:
先取奇数集中 20 个元素1,再取偶数集中 21 个元素2,4;
再取奇数集中 22素 {3,5,7,9},再取偶数集中 23 个元素 {6,8,10……};
............
得到 {1,2,4,3,5,7,9,6,8,10,12……} ;
问这个数组的某一区间 [l,r] 的区间和是多少,并对1e9+7取模。
思路一:
分别求出区间[l,r]对应的 {oddS,oddE},{evenS,evenE}
oddS:区间[l,r]的第一个奇数
oddE:区间[l,r]的最后一个奇数
evenS,evenE同理;
(oddSum:{oddS,....,oddE}之间的奇数个数,evenSum同理)
最后输出ans%mod即可;
AC代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 const int mod=1e9+7; 5 6 ll l,r; 7 8 ll fOdd(int x)///找2^x个连续的奇数开始的奇数 9 { 10 ll tot=((1ll*1<<x)-1)/3; 11 return 1+(tot<<1); 12 } 13 ll fEven(int x)///找2^x个连续的偶数开始的偶数 14 { 15 ll tot=((1ll*1<<x)-2)/3; 16 return 2+(tot<<1); 17 } 18 ll quickPower(ll _a,ll _b,ll _mod) 19 { 20 ll ans=1; 21 while(_b) 22 { 23 if(_b&1) 24 ans=ans*_a%mod; 25 _a=(_a*_a)%mod; 26 _b >>= 1; 27 } 28 return ans; 29 } 30 ll Solve() 31 { 32 int x,y; 33 for(x=0;(1ll*1<<(x+1))-1 < l;++x);///包含l的最大的x 34 for(y=0;(1ll*1<<(y+1))-1 < r;++y);///包含r的最大的y 35 36 ll oddS=!(x&1)/**判断x是否为偶数*/ ? fOdd(x)+(l-(1ll*1<<x))*2:fOdd(x+1); 37 ll evenS=(x&1)/**判断x是否为奇数*/ ? fEven(x)+(l-(1ll*1<<x))*2:fEven(x+1); 38 39 ll oddE=!(y&1) ? fOdd(y)+(r-(1ll*1<<y))*2:fOdd(y+1)-2; 40 ll evenE=(y&1) ? fEven(y)+(r-(1ll*1<<y))*2:fEven(y+1)-2; 41 42 ll ans=0; 43 if(oddE >= oddS) 44 { 45 ll n=((oddE-oddS)>>1)+1; 46 ll d=oddE+oddS; 47 ///被除数2可以将其约掉(d肯定为偶数) 48 ///也可以用逆元进行除法取模 49 ///我用的是逆元除法取模(有点麻烦) 50 ans += ((n%mod)*(d%mod)%mod)*(quickPower(2,mod-2,mod))%mod; 51 } 52 if(evenE >= evenS) 53 { 54 ll n=((evenE-evenS)>>1)+1; 55 ll d=evenE+evenS; 56 ans += ((n%mod)*(d%mod)%mod)*(quickPower(2,mod-2,mod))%mod; 57 } 58 return ans%mod; 59 } 60 int main() 61 { 62 // freopen("C:\\Users\\hyacinthLJP\\Desktop\\in&&out\\contest","r",stdin); 63 scanf("%lld%lld",&l,&r); 64 printf("%lld\n",Solve()); 65 return 0; 66 }
思路二:
前 i 个偶数的和为 i*(i+1)
前 i 个奇数的和为 i*i
求解出前 r 个奇数,偶数个数,求出答案
求解出前 l-1 个奇数,偶数个数,求出答案,两者做差便是最终答案
AC代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 const int mod=1e9+7; 5 6 ll l,r; 7 8 ll Solve(ll x)///分别求解出[1,x]中奇数个数,偶数个数 9 { 10 ll oddSum=0; 11 ll evenSum=0; 12 for(int i=0;;i++) 13 { 14 if((1ll*1<<(i+1))-1 >= x)///包含x的最大的2^i 15 { 16 if(i&1) 17 evenSum += (x-(1ll*1<<i)+1)%mod; 18 else 19 oddSum += (x-(1ll*1<<i)+1)%mod; 20 break; 21 } 22 if(i&1) 23 evenSum += (1ll*1<<i)%mod; 24 else 25 oddSum += (1ll*1<<i)%mod; 26 evenSum %= mod; 27 oddSum %= mod; 28 } 29 ///[1,x]的区间和 30 return (evenSum%mod*(evenSum+1)%mod%mod+oddSum%mod*(oddSum%mod)%mod)%mod; 31 } 32 int main() 33 { 34 // freopen("C:\\Users\\hyacinthLJP\\Desktop\\in&&out\\contest","r",stdin); 35 scanf("%lld%lld",&l,&r); 36 37 ///注意,取模做减法有可能变成负值,需要再加个mod,再模一次mod 38 printf("%lld\n",(Solve(r)-Solve(l-1)+mod)%mod); 39 40 return 0; 41 }