hdu5230 L到R之间每个数可以拆成多少种不重复正整数和的方案数 dp/计数

先对一个数来看,注意到拆成的每个正整数只能用一次,也就是100000内的数最多拆成400+个

然后来寻找递推,dp[i][j]表示j拆成i个数的方案,这个时候可以i个数都加1,或者新增一个1,问题来了,不能确定原来i个是否有1,所以再开一维[0/1]表示i个数有没有1

得到递推式:

dp[i][j][0]表示最小数不为1,dp[i][j][1]表示最小数为1

1 add(dp[i][j+i][0],dp[i][j][0]+dp[i][j][1]);
2 add(dp[i+1][j+1][1],dp[i][j][0]); 

这样就会得到MLE,再加一个滚动数组即可AC本题

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<algorithm>
 4 #define MOD 998244353
 5 using namespace std;
 6 int Now[101005][2],Next[101005][2],s[101005];
 7 void add(int &x,int y)
 8 {
 9   if (y>MOD) y-=MOD;
10   x+=y;
11   if (x>MOD) x-=MOD;
12 } 
13 int main()
14 {
15   int i,j,T,c,n,l,r;
16   memset(s,0,sizeof(s));
17   Next[1][1]=1;
18   for (i=1;i<=450;i++)
19   {
20     for (j=1;j<=100000;j++) 
21     {
22       Now[j][0]=Next[j][0]; Next[j][0]=0;
23       Now[j][1]=Next[j][1]; Next[j][1]=0;
24     }
25     for (j=i;j<=100000;j++)
26     {
27       add(Now[j+i][0],Now[j][0]+Now[j][1]);
28       add(Next[j+1][1],Now[j][0]);
29     }
30     for (j=1;j<=100000;j++) add(s[j],Now[j][0]+Now[j][1]);
31   }
32   s[0]=1;
33   for (i=1;i<=100000;i++) add(s[i],s[i-1]);
34   scanf("%d",&T);
35   while (T--)
36   {
37     scanf("%d%d%d%d",&n,&c,&l,&r);
38     l-=c; r-=c; c=s[r];
39     if (l!=0) c=s[r]-s[l-1];
40     if (c<0) c+=MOD;
41     printf("%d\n",c);
42   }
43   return 0;
44 }
View Code

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5230

posted on 2015-05-17 01:40  xiao_xin  阅读(409)  评论(3编辑  收藏  举报

导航