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

5 篇文章 0 订阅

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
 

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);
	}
}


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值