题目大意:求1-10^9中各个位上的数的和为S的数的个数。
Time Limit:1000MS Memory Limit:65536KB 64bit IO Format:%I64d & %I64u
数据规模:1<=S<=81。
理论基础:无(dp题的关键在于状态与状态转移方程,理论什么的都貌似没多少)。
题目分析:用dp[i][j]表示n位数的各个位数和为j的个数。状态转移方程:dp[i][j]=sum(dp[i-1][j-k],0<k<10&&k<j)。答案就是:ans=sum(dp[i][S],1<=i<=9)+(S==1)(10^9单独处理)
But,这道题,由于规模太小我没们不用dp,那用什么?枚举呗,枚举打表就可以了。我们可以观察到:S=99与S=0是相等的,S=98与S==1(不计10^9时)是相等的,S=97与S=2是相等的,这不是偶然,是因为1用8替换,2用7替换,...。这样的话我们就只需要枚举到S=44就可以了,然后打表。O(1)解决此问题。
至于dp的方法大家可以下去试一下。这里不再详细说明。
代码如下:
#include<iostream>
#include<cstring>
#include<string>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<ctime>
#include<vector>
using namespace std;
typedef double db;
#define DBG 0
#define maa (1<<31)
#define mii ((1<<31)-1)
#define ast(b) if(DBG && !(b)) { printf("%d!!|\n", __LINE__); while(1) getchar(); } //调试
#define dout DBG && cout << __LINE__ << ">>| "
#define pr(x) #x"=" << (x) << " | "
#define mk(x) DBG && cout << __LINE__ << "**| "#x << endl
#define pra(arr, a, b) if(DBG) {\
dout<<#arr"[] |" <<endl; \
for(int i=a,i_b=b;i<=i_b;i++) cout<<"["<<i<<"]="<<arr[i]<<" |"<<((i-(a)+1)%8?" ":"\n"); \
if((b-a+1)%8) puts("");\
}
template<class T> inline bool updateMin(T& a, T b) { return a>b? a=b, true: false; }
template<class T> inline bool updateMax(T& a, T b) { return a<b? a=b, true: false; }
typedef long long LL;
typedef long unsigned int LU;
typedef long long unsigned int LLU;
int ans[82]={1,10,45,165,495,1287,3003,6435,12870,24310,43749,75501,125565,
202005,315315,478731,708444,1023660,1446445,2001285,2714319,3612231,4720815,
6063255,7658190,9517662,11645073,14033305,16663185,19502505,22505751,25614639,
28759500,31861500,34835625,37594305,40051495,42126975,43750575,44865975,45433800,
45433800,44865975,43750575,42126975,40051495,37594305,34835625,31861500,28759500,
25614639,22505751,19502505,16663185,14033305,11645073,9517662,7658190,6063255,4720815,
3612231,2714319,2001285,1446445,1023660,708444,478731,315315,202005,125565,75501,
43749,24310,12870,6435,3003,1287,495,165,45,9,1},s;
int main()
{
if(DBG)
{
for(int i=2;i<=81;i++)
{
int cnt=0;
for(int i_a=0;i_a<=9;i_a++)
{
if(i_a>i)break;
for(int i_b=0;i_b<=9;i_b++)
{
if(i_a+i_b>i)break;
for(int i_c=0;i_c<=9;i_c++)
{
if(i_a+i_b+i_c>i)break;
for(int i_d=0;i_d<=9;i_d++)
{
if(i_a+i_b+i_c+i_d>i)break;
for(int i_e=0;i_e<=9;i_e++)
{
if(i_a+i_b+i_c+i_d+i_e>i)break;
for(int i_f=0;i_f<=9;i_f++)
{
if(i_a+i_b+i_c+i_d+i_e+i_f>i)break;
for(int i_g=0;i_g<=9;i_g++)
{
if(i_a+i_b+i_c+i_d+i_e+i_f+i_g>i)break;
for(int i_h=0;i_h<=9;i_h++)
{
if(i_a+i_b+i_c+i_d+i_e+i_f+i_g+i_h>i)break;
for(int i_i=0;i_i<=9;i_i++)
{
if(i_a+i_b+i_c+i_d+i_e+i_f+i_g+i_h+i_i>i)break;
if(i_a+i_b+i_c+i_d+i_e+i_f+i_g+i_h+i_i==i)cnt++;
}
}
}
}
}
}
}
}
}
printf(",%d",cnt);
}
}
else
{
while(~scanf("%d",&s))
{
printf("%d\n",ans[s]);
}
}
return 0;
}
其中DBG在以前的博文里已经解释过了,打表时把DBG改为1,打好表后,提交代码时改为0即可。
by:Jsun_moon http://blog.youkuaiyun.com/Jsun_moon