bzoj 1581: [Usaco2009 Hol]Transmission Delay 传输谍延时
Description
约翰在屋顶上唱歌,以此来与奶牛们交流.但是奶牛们的听力很奇怪,她们只能听到约翰的歌声变成0和1构成的信息串时的样子. 约翰的声音里有N(1≤N≤2000)个0或1,奶牛听到的也是N个,而且0和1的数量不会变化,但是一部分0或1可能偏离原来的位置,这就是约翰的歌声在传输时发生的“传输延迟”现象.0或1的偏离距离不会超过D(O≤D<N),也就是说某一个码的原本位置和现在的位置之差的绝对值不大于D.
比如,对于0110,D=1,传输延迟发生后可能出现0101,0110,1001,1010这四种串.
给出约翰歌声的01串形式和一个整数K(1≤K≤108),请计算传输延迟发生后一共有多少种可能的01串,以及其中第K大的串是什么.
Input
第一行输入 n , d , k 第二行输入那个N位的数字,用二进制表示
Output
分别输出受到整数的种数(将结果Mod 100,000,000),和这些整数第K小的那个
Sample Input
4 1 3
0110
0110
Sample Output
4
1001
1001
HINT
1<=n<=2000 0<=k
Source
这题是个dp。
定义方程f[i][j]表示从n~i,用了j个0的方案数。要n~i倒着处理是为之后的第k大做帮助。
第一问就直接dp,我们记录下p0[i],p1[i]分别表示从左往右第i个0的位置,第i个1的位置。转移的时候根据当前位放0还是放1,且是否满足距离小于等于d,计算即可。
然后对于第二问,我们这么做:
-
如果当前位置放0的方案数>=k,当前位就放0。
-
如果不能放0,就放1,并且k减去放0的方案数。
以上所有说的可以放0或放1都是建立在题目要求的前提下的,即距离不超过d
然后我们有一个问题了:如果方案数超过k的超过太多了怎么办?按照题意来说我们应该是要%10^8的,但是由于要求后面的第k大需要用到这个方案数,如果我们直接%10^8,就会导致结果不正确了。
对于这个问题我们再开一个g[i][j]也记录方案数,如果g[i][j]>10^8了就把它设成10^8+1,然后之后算第k大的时候就用g[i][j]当做方案数,这样就没事了。
下面放代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 int const N=2000+3; 4 int const mod=1e8; 5 int f[N][N],g[N][N],s0,s1,p0[N],p1[N],n,d,k; 6 char s[N]; 7 int main(){ 8 scanf("%d%d%d",&n,&d,&k); 9 scanf("%s",s+1); 10 for(int i=1;i<=n;i++) 11 if(s[i]==48) p0[++s0]=i; 12 else p1[++s1]=i; 13 f[n+1][0]=g[n+1][0]=1; 14 for(int i=n;i>=1;i--) 15 for(int j=0;j<=s0;j++) { 16 if(j && abs(p0[s0-j+1]-i)<=d) 17 { 18 f[i][j]+=f[i+1][j-1]; 19 f[i][j]%=mod; 20 g[i][j]+=g[i+1][j-1]; 21 if(g[i][j]>mod) g[i][j]=mod+1; 22 } 23 if(n-i+1-j<=s1 && abs(p1[s1-(n-i+1-j)+1]-i)<=d) { 24 f[i][j]+=f[i+1][j]; 25 f[i][j]%=mod; 26 g[i][j]+=g[i+1][j]; 27 if(g[i][j]>mod) g[i][j]=mod+1; 28 } 29 } 30 printf("%d\n",f[1][s0]); 31 int num0=s0,num1=s1; 32 for(int i=1;i<=n;i++) { 33 if(num0 && abs(p0[s0-num0+1]-i)<=d) 34 { 35 if(g[i+1][num0-1]>=k) putchar('0'),num0--; 36 else putchar('1'),k-=g[i+1][num0-1],num1--; 37 } 38 else num1--,putchar('1'); 39 } 40 return 0; 41 }