USACO Training3.2 01串 By cellur925
一句话题意:求长度为n的有m个1的大小为第k个的01串。
暑假我做的时候是真·大暴力,用二进制枚举,55分,成功T掉无数点。
正解:开始可以用计数类dp来“预处理”,状态和转移都比较好想。
状态:设f[i][j]表示i位二进制数,1的个数不超过j的种类数。
转移:f[i][j]=f[i-1][j]+f[i-1][j-1] (当前位取0或1)
初值:f[i][0]=0,f[0][i]=0;
然后?我们尝试倒序枚举答案。我们知道在二进制中最高位为1时一定比最高位为0的情况大,所以我们在尝试的过程中,如果当前的k仍大于f[i-1][j],则第i位一定为1,因为还没达到第k个的要求。所以我们不断将k减去f[i-1][j],这样不断向下枚举就能得到答案。
Code
1 #include<cstdio> 2 #include<algorithm> 3 4 using namespace std; 5 typedef long long ll; 6 7 int n,m; 8 ll pos,f[100][100]; 9 10 int main() 11 { 12 scanf("%d%d%lld",&n,&m,&pos); 13 for(int i=0;i<=n;i++) f[i][0]=1,f[0][i]=1; 14 for(int i=1;i<=n;i++) 15 for(int j=1;j<=m;j++) 16 if(j<=i) f[i][j]=f[i-1][j]+f[i-1][j-1]; 17 else f[i][j]=f[i][i]; 18 int a=n,b=m; 19 while(a!=0) 20 { 21 if(pos>f[a-1][b]) 22 { 23 pos-=f[a-1][b]; 24 printf("1"); 25 a--;b--; 26 } 27 else 28 { 29 printf("0"); 30 a--; 31 } 32 } 33 printf("\n"); 34 return 0; 35 }
* 注意:开long long 。防止越界。(2^31)
独立意志与自由思想是必须争的,且须以生死力争。