hdu 5656 CA Loves GCD(dp+gcd)(Bestcoder #78 1002)

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 535    Accepted Submission(s): 188


Problem Description
CA is a fine comrade who loves the party and people; inevitably she loves GCD (greatest common divisor) too. 
Now, there are  N  different numbers. Each time, CA will select several numbers (at least one), and find the GCD of these numbers. In order to have fun, CA will try every selection. After that, she wants to know the sum of all GCDs. 
If and only if there is a number exists in a selection, but does not exist in another one, we think these two selections are different from each other.
 

Input
First line contains  T  denoting the number of testcases.
T  testcases follow. Each testcase contains a integer in the first time, denoting  N , the number of the numbers CA have. The second line is  N  numbers. 
We guarantee that all numbers in the test are in the range [1,1000].
1T50
 

Output
T  lines, each line prints the sum of GCDs mod  100000007 .
 

Sample Input
   
   
   
   
2 2 2 4 3 1 2 3
 

Sample Output
   
   
   
   
8 10
 

Source
BestCoder Round #78 (div.2)
 

Recommend
wange2014
 


题目大意:

       给定一个序列a,从中取出若干个数字求gcd,求解所有抽取方案的gcd之和

解题思路:

      dp[i][j]表示序列a从0到i的数中,取出的gcd为j的方案数。那么对于每个i,dp[i+1][j]由三部分组成,选a[i+1]也选择前面的,只选a[i+1],只选前面的,所以有:

      dp[i+1][j]=sigema(dp[i][m])(满足gcd(m,a[i+1])=j,m>=1&&m<=1000)

                        +dp[i][j]

                       +(a[i]==j)

      最后的ans=sigema(dp[n-1][j]*j)(满足j>=1&&j<=1000)

p.s.:1.求解gcd(m,a[i+1])=j的数的时候,如果直接遍历会T,要先预处理,找到每一个和a[i+1]/j互素的数字,把他乘上j就是m

           2.dp数组别忘了可能超过int,要用ll+取摸

           3.题干中说的不同方案其实是一个方案中有一个数下标和另一个方案里中不同就可以

<pre name="code" class="cpp">#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<queue>
#include<stack>
#define ll long long
#define INF 0x3f3f3f3f
#define C(a) memset(a,0,sizeof a)
#define C_1(a) memset(a,-1,sizeof a)
#define C_i(a) memset(a,0x3f,sizeof a)
#define F(i,n) for(int i=0;i<n;i++)
#define F(n) for(int i=0;i<n;i++)
#define F_1(n) for(int i=n;i>0;i--)

#define S(a) scanf("%d",&a);
#define S2(a,b) scanf("%d%d",&a,&b);
#define SL(a) scanf("%I64d",&a);
#define SD(a) scanf("%lf",&a);
#define P(a) printf("%d\n",a);
#define PL(a) cout<<a<<endl;
#define PD(a)printf("%lf\n",a);

#define rush() int t;scanf("%d",&t);while(t--)
#define mod 100000007
using namespace std;

vector<int>v[1005];
ll dp[1005][1005];
int a[1005];;
int gcd(int a, int b)
{
	while (a&&b)
	{
		if (a > b)a = a%b;
		else b = b%a;
	}
	return a + b;
}
void init()
{
	for (int i = 1; i < 1005; i++)
		for (int j = 1; j <1005; j++)
			if (gcd(i, j) == 1)v[i].push_back(j);
}
int main()
{
	ll ans = 0;
	init();
	rush()
	{
		ans = 0;
		C(a); C(dp);
		int n, tem;
		S(n);
		for (int i = 0; i < n; i++)S(a[i]);
		dp[0][a[0]] = 1;
		for (int i = 1; i < n; i++)
			for (int j = 1; j <= 1000; j++)
			{
				ll cnt = dp[i - 1][j] + (a[i] == j);
				int k = 2;
				if (!(a[i] % j))
				{
					int tem=a[i]/j;
					for (int k = 0; k < v[tem].size()&&j*v[tem][k]<1005; k++)
						cnt = (dp[i - 1][j*v[tem][k]]+cnt)%mod;
				}//不预处理会超时
				dp[i][j] = cnt;
			}
		for (int i = 1; i <= 1000; i++)ans = (ans + i*dp[n - 1][i]) % mod;
		PL(ans);
	}
}


 
 

你可能感兴趣的:(dp,HDU,BestCoder)