一个密钥是一个长度为 k=3 时,BAXABAB 就是一个密钥。
如下图所示,可以按顺时针顺序把这 2k+1 个字母排成一个圈:
在
具体来说,从 X 出发顺时针走到某个 A 时,如果途中 A 的数目严格多于 B 的数目,则称此字母 A 为强的。
对于上面的例子来说,顺时针方向从字母 X 数起第 3 个字母 A 不是强的。
一个密钥的特征值就是其中包含的强的字母 A 的个数。
天才小朋友 KT 给出了一个结论:
假设 k+1 个可能的位置。)
可以证明:所有这0,1,2,…,k。
下页的图是一个具体的示例,从左到右的四个子图中分别有3个,2个,1个,0个字母A是强的。
类似地,如果固定 0,1,⋯,k。
现在你需要解决以下三个问题:
- 给定密钥中所有 A 的位置,当密钥的特征值为 0 时,请问 X 在哪个位置。
- 给定密钥中所有 A 的位置,当密钥的特征值为 S 时,请问 X 在哪个位置。
- 给定密钥中所有 B 的位置,当密钥的特征值为 S 时,请问 X 在哪个位置。
注意:字符串的 2k+1 编号。
例子一
假定 k=3,S=2。那么:
当 A 的位置是 7;
当 A 的位置是 3;
当 B 的位置是 5。
例子二
假定 k=9,S=7。那么:
当 A 的位置是 14;
当 A 的位置是 18;
当 B 的位置是 17。
输入格式
只包含一组测试数据。
第一行包含一个整数k,意义如题所述。
第二行包含一个整数k元集合P。
第三行包含一个整数S,意义如题所述。
保证1≤seed≤10000。
在下发文件中,包含三个用于生成输入数据的文件cipher.cpp/c/pas。其中读入部分已经完成,在数组 P。
输出格式
输出三行,每行一个数,依次对应问题描述中的三个子问题的答案。
即:
- 第一个数表示当 0 时 X 的位置。
- 第二个数表示当 S 时 X 的位置。
- 第三个数表示当 S 时 X 的位置。
样例一
input
5 3344 2
output
10 1 2
explanation
第一个样例中,5,6,7,8,9。
样例二
input
500000 4545 234567
output
999992 246922 753067
限制与约定
对于 k≤103。
对于 k≤105。
对于 k≤107。
对于每个测试点,得分为以下三部分得分之和:
- 如果第一问回答正确,你将获得 3 分。
- 如果第二问回答正确,你将获得 4 分。
- 如果第三问回答正确,你将获得 3 分。
如果你仅仅知道部分答案,请也务必按此格式要求输出三个数。否则你可能会因格式错误无法得分。
时间限制:1s
空间限制:MB
#include<iostream> #include<cstdio> #include<cstring> #define maxn 20000005 using namespace std; int p[maxn],b[maxn],cnt,ans[maxn]; int seed, n, k, S; int getrand() { seed = ((seed * 12321) ^ 9999) % 32768; return seed; } void generateData() { scanf("%d%d%d",&k,&seed,&S); int t = 0; n = k * 2 + 1; memset(p, 0, sizeof(p)); for (int i = 1; i <= n; i++) { p[i] = (getrand() / 128) % 2; t += p[i]; } int i = 1; while (t > k) { while (p[i] == 0) i++; p[i] = 0; t--; } while (t < k) { while (p[i] == 1) i++; p[i] = 1; t++; } } int count1(int s){ int sa=0,sb=0,res=0; for(int i=2,j=s+1;i<=n;i++,j++){ if(p[j]==0)sb++; else { sa++; if(sa>sb)res++; } } return res; } void work1(){ for(int i=1;i<=cnt;i++)//x的位置 ans[i]=count1(b[i]); } int count2(int s){ int sa=0,sb=0,res=0; for(int i=2,j=s+1;i<=n;i++,j++){ if(p[j]==1)sb++; else { sa++; if(sa>sb)res++; } } return res; } void work2(){ for(int i=1;i<=cnt;i++) ans[i]=count2(b[i]); } int main(){ generateData(); for(int i=1;i<=n;i++)p[i-1]=p[i]; for(int i=0;i<n;i++)p[i+n]=p[i]; for(int i=0;i<n;i++)if(!p[i])b[++cnt]=i; if(k<=1000){ work1(); int ans0,ans1; for(int i=1;i<=cnt;i++){ if(ans[i]==0)ans0=b[i]+1; if(ans[i]==S)ans1=b[i]+1; } printf("%d\n%d\n",ans0,ans1); work2(); for(int i=1;i<=cnt;i++) if(ans[i]==S){ printf("%d\n",b[i]+1); return 0; } } return 0; }