Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 3247 | Accepted: 2136 |
Description
So you are to save public transport of our city. Write a program that determines a number of lucky tickets for the given number of digits. By the way, there can't be more than 10 digits on one ticket.
Input
Output
Sample Input
4
Sample Output
670
题意是要找幸运数字,所谓幸运数字就是一个n位(n为偶数)的数字,前n/2位每位的数字和与后n/2位的数字和相等。
因为这题第一位0也包括进去了,题目难度减少好多。
然后一看n最大才10,难度一下子下降更多了。就不管dp了,直接打表暴力。
幸好是最大是10,电脑跑了一会才有结果。要是12估计电脑都会跑好久。
暴力代码(n为10时):
#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
int main()
{
int i1,i2,i3,i4,i5,i6,i7,i8,i9,i10,result=0;
for(i1=0;i1<=9;i1++)
for(i2=0;i2<=9;i2++)
for(i3=0;i3<=9;i3++)
for(i4=0;i4<=9;i4++)
for(i5=0;i5<=9;i5++)
for(i6=0;i6<=9;i6++)
for(i7=0;i7<=9;i7++)
for(i8=0;i8<=9;i8++)
for(i9=0;i9<=9;i9++)
for(i10=0;i10<=9;i10++)
if(i1+i2+i3+i4+i5==i6+i7+i8+i9+i10)
result++;
cout<<result<<endl;
system("pause");
return 0;
}
#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
int main()
{
int result[12],n;
result[0]=0;
result[2]=10;
result[4]=670;
result[6]=55252;
result[8]=4816030;
result[10]=432457640;
cin>>n;
cout<<result[n]<<endl;
return 0;
}
这么一看这道题还真是水啊。。。
以上是我2015年7月11日时犯下的二逼想法,等到我10月份做到51nod1043的幸运数字时,想起了2346discuss上面的一个dp,于是就顺着那个思路去想了。然后就一直wa。
才发现其实这个dp很简单,远远没有我之前想得那么麻烦。
用dp[i][j]表示i个数的和为j的总数,这里面是包括0开头的情形,有dp[i][j]=dp[i-1][j-k](k从0到9)。很好想,i个数组成总和为j的数量就来自于i-1个数 里面能 在最前面加0到9的数字使得加完之后和为j。
这里面包含了0开头的,把0去掉的方法就是dp[i][j]-dp[i-1][j]。dp[i-1][j]就代表了在i个数中,开头为0的个数,减去就是i个数中开头不为0的个数。原因很明显,i个数和为j与i-1个数和为j,就差了一个位置为0。而这一个位置因为一开始咱们的想法就是在最前面加的数字,所以这个位置就差在了最前面的位置上。
所以根据51nod 又把poj2346的代码改了一下,就是
#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
#include <string>
#include <cstring>
#pragma warning(disable:4996)
using namespace std;
#define maxn 1005
const int mod = 1000000007;
long long dp[2][9*maxn];
int n;
int main()
{
//freopen("i.txt","r",stdin);
//freopen("o.txt","w",stdout);
int i,j,k;
long long ans;
cin>>n;
n=n/2;
memset(dp,0,sizeof(dp));
//dp[0][1]=1;//此处单独为了1 考虑
for(i = 0; i <= 9; ++ i)
{
dp[1][i] = 1;
}
for(i=2;i<=n;i++)
{
for(k=0;k<=n*9;k++)
{
long long sum=0;
for(j=0;j<=9;j++)
{
if(k>=j)
sum = (sum+dp[(i-1)&1][k-j])%mod;
else
dp[i&1][k]=0;
}
dp[i&1][k]=sum;
}
}
ans=0;
for(i=0;i<=n*9;i++)
{
ans = (ans+dp[n&1][i]*(dp[n&1][i]))%mod;
}
cout<<ans<<endl;
//system("pause");
return 0;
}
当然,题目没有要求mod 1e9+7。
然后是51nod1043 幸运号码:
输入N(1<= N <= 1000)
输出幸运号码的数量 Mod 10^9 + 7
1
9
代码:
#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
#include <string>
#include <cstring>
#pragma warning(disable:4996)
using namespace std;
#define maxn 1005
const int mod = 1000000007;
long long dp[2][9*maxn];
int n;
int main()
{
//freopen("i.txt","r",stdin);
//freopen("o.txt","w",stdout);
int i,j,k;
long long ans;
cin>>n;
memset(dp,0,sizeof(dp));
dp[0][1]=1;//此处单独为了1 考虑
for(i = 0; i <= 9; ++ i)
{
dp[1][i] = 1;
}
for(i=2;i<=n;i++)
{
for(k=0;k<=n*9;k++)
{
long long sum=0;
for(j=0;j<=9;j++)
{
if(k>=j)
sum = (sum+dp[(i-1)&1][k-j])%mod;
else
dp[i&1][k]=0;
}
dp[i&1][k]=sum;
}
}
ans=0;
for(i=0;i<=n*9;i++)
{
ans = (ans+dp[n&1][i]*(dp[n&1][i]-dp[(n-1)&1][i]))%mod;
}
cout<<ans<<endl;
//system("pause");
return 0;
}
发现就是不断看自己写过的笔记,也在发现自己得到的成长。三个月的时间,和之前的很多想法都不太一样了。