今天的题还是比较水的。。涨自信?
第一题。。显而易见的dp:dp[i][j][k][l][m]:表示i位,j个1,k是否顶上界,l个前导零,是否仍在前导零上。转移方程比较复杂,详见代码。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 long long dp[50][50][2][50][2]; 6 long long work(long long x) 7 { 8 long long top[200]; 9 memset(dp,0,sizeof(dp)); 10 memset(top,0,sizeof(top)); 11 long long i=1; 12 long long j=1; 13 if(x==0) return 0; 14 while(x/j) 15 { 16 i++; 17 j*=2; 18 } 19 if(i) 20 i--; 21 long long n=i; 22 while(x) 23 { 24 top[i]=x%2; 25 x/=2; 26 i--; 27 } 28 // for(int i=1;i<=n;i++) 29 // cout<<top[i]; 30 // cout<<endl<<endl; 31 dp[1][0][1][0][0]=1; 32 // for(int i=1;i<=n;i++) 33 // cout<<top[i]; 34 // cout<<endl; 35 for(i=1;i<=n;i++) 36 for(j=0;j<=n/2;j++) 37 for(int k=0;k<=n;k++) 38 { 39 dp[i+1][j][0][k+1][0]+=dp[i][j][0][k][0]; 40 dp[i+1][j+1][0][k][1]+=dp[i][j][0][k][0]; 41 if(top[i]==0) 42 dp[i+1][j][1][k+1][0]+=dp[i][j][1][k][0]; 43 else 44 { 45 dp[i+1][j][0][k+1][0]+=dp[i][j][1][k][0]; 46 dp[i+1][j+1][1][k][1]+=dp[i][j][1][k][0]; 47 } 48 for(long long l=0;l<=1;l++) 49 dp[i+1][j+l][0][k][1]+=dp[i][j][0][k][1]; 50 for(long long l=0;l<=top[i];l++) 51 dp[i+1][j+l][l==top[i]][k][1]+=dp[i][j][1][k][1]; 52 // cout<<dp[i][j][up]<<endl; 53 } 54 long long ans=0; 55 for(int k=0;k<=n;k++) 56 for(int i=1;i<=(n-k)/2;i++) 57 { 58 ans+=dp[n+1][i][0][k][1]+dp[n+1][i][1][k][1]; 59 } 60 61 // for(int j=1;j<=n+1;j++) 62 // for(int k=0;k<=n;k++) 63 // for(int i=1;i<=n;i++) 64 // cout<<dp[j][i][0][k][1]; 65 return ans; 66 } 67 void work() 68 { 69 freopen("testA.in","r",stdin); 70 freopen("testA.out","w",stdout); 71 long long L,R; 72 cin>>L>>R; 73 if(L==1) 74 cout<<work(R)<<endl; 75 else 76 cout<<work(R)-work(L-1)<<endl; 77 // cout<<work(R)<<" "<<work(L-1)<<endl; 78 } 79 int main() 80 { 81 work(); 82 return 0; 83 }
第二题比较复杂,大意就是把[ai,bi] 作为区间,落在[1,N]上,互不重叠,长度互不相等。然后dp[j][k]表示在i位,选了k个,其和为j。
然后答案就是,详见标程代码(我还没有写出来)。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<string> 5 using namespace std; 6 const long long MOD =1000000007LL; 7 long long dp[1007][1007]; 8 long long C[2014][2014]; 9 long long x[101]; 10 #ifdef unix 11 #define LL "%lld " 12 #else 13 #define LL "I64d " 14 #endif 15 void init() 16 { 17 memset(dp,0,sizeof(dp)); 18 memset(C,0,sizeof(C)); 19 memset(x,0,sizeof(x)); 20 x[0]=1; 21 for(int i=1;i<=100;i++) 22 x[i]=x[i-1]*i%MOD; 23 for(int i=1;i<1000;i++) 24 { 25 C[i][i]=1; 26 C[i][0]=1; 27 for(int j=1;j<i;j++) 28 { 29 C[i][j]=(C[i-1][j]+C[i-1][j-1])%MOD; 30 } 31 } 32 dp[0][0]=1; 33 for(int i=1;i<=1000;i++) 34 for(int j=1000;j>=i;j--) 35 for(int k=50;k>0;k--) 36 dp[k][j]=(dp[k][j]+dp[k-1][j-i])%MOD; 37 } 38 int main() 39 { 40 init(); 41 int T,N,K; 42 cin>>T; 43 long long ans=0; 44 while(T--) 45 { 46 cin>>N>>K; 47 if(K*(K+1)/2>N) 48 { 49 printf("0 "); 50 continue; 51 } 52 ans=0; 53 for(int L=K;L<=N;L++) 54 { 55 ans=(ans+dp[K][L]*C[N+K-L][K]%MOD)%MOD; 56 } 57 printf("%lld ",(ans*x[K])%MOD); 58 } 59 }
第三题比较水,我就不多说什么了,多特判就好了。。
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 int main() 5 { 6 freopen("testC.in","r",stdin); 7 freopen("testC.out","w",stdout); 8 int n,m,x; 9 cin>>n>>m>>x; 10 if(x<0) 11 { 12 cout<<0<<endl; 13 return 0; 14 } 15 if(x==0) 16 { 17 cout<<n*m/2<<endl; 18 return 0; 19 } 20 x-=1; 21 n-=2*x; 22 m-=2*x; 23 if(n<=0||m<=0) 24 cout<<0<<endl; 25 else if(n==1||m==1) 26 cout<<n*m-n*m/2<<endl; 27 else 28 cout<<(n+m)-2<<endl; 29 return 0; 30 }