51nod1043 && POJ 2346:幸運號碼

Lucky tickets
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 3247   Accepted: 2136

Description

The public transport administration of Ekaterinburg is anxious about the fact that passengers don't like to pay for passage doing their best to avoid the fee. All the measures that had been taken (hard currency premiums for all of the chiefs, increase in conductors' salaries, reduction of number of buses) were in vain. An advisor especially invited from the Ural State University says that personally he doesn't buy tickets because he rarely comes across the lucky ones (a ticket is lucky if the sum of the first three digits in its number equals to the sum of the last three ones). So, the way out is found — of course, tickets must be numbered in sequence, but the number of digits on a ticket may be changed. Say, if there were only two digits, there would have been ten lucky tickets (with numbers 00, 11, ..., 99). Maybe under the circumstances the ratio of the lucky tickets to the common ones is greater? And what if we take four digits? A huge work has brought the long-awaited result: in this case there will be 670 lucky tickets. But what to do if there are six or more digits? 
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

Input contains a positive even integer N not greater than 10. It's an amount of digits in a ticket number.

Output

Output should contain a number of tickets such that the sum of the first N/2 digits is equal to the sum of the second half of digits.

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 幸運號碼:

基準時間限制:1 秒 空間限制:131072 KB 分值: 20 難度:3級算法題
 收藏
 取消關注
1個長度爲2N的數,如果左邊N個數的和 = 右邊N個數的和,那麼就是一個幸運號碼。
例如:99、1230、123312是幸運號碼。
給出一個N,求長度爲2N的幸運號碼的數量。由於數量很大,輸出數量 Mod 10^9 + 7的結果即可。
Input
輸入N(1<= N <= 1000)
Output
輸出幸運號碼的數量 Mod 10^9 + 7
Input示例
1
Output示例
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;
}
發現就是不斷看自己寫過的筆記,也在發現自己得到的成長。三個月的時間,和之前的很多想法都不太一樣了。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章