您的位置:首页 > 其它

HDU 5656 CA Loves GCD

2016-04-26 19:32 375 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5656

题意:有N个不同的数,每次从中选出若干个(至少一个数),求出所有数的GCD然后放回去。求所有选择的GCD之和是多少。

思路:由于每个数的范围很小,所以用dp[i][j]来表示前i个数中选取若干个使得gcd为j的方案总数。

1、不选取ai,dp[i][j]+=dp[i-1][j]

2、选取ai,dp[i][ai]++ dp[i][gcd(ai,j)]+=dp[i-1][j]

再用一个数组记录一下gcd,不然可能会超时。

#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <sstream>
#include <queue>
#include <utility>
using namespace std;

#define rep(i,j,k) for (int i=j;i<=k;i++)
#define Rrep(i,j,k) for (int i=j;i>=k;i--)

#define Clean(x,y) memset(x,y,sizeof(x))
#define LL long long
#define ULL unsigned long long
#define inf 0x7fffffff
#define mod %100000007
const int maxn = 1002;

LL dp[maxn][maxn];
int n,T;
int a[maxn];

int g[maxn][maxn];

int gcd(int a,int b)
{
if ( g[a][b] != -1 ) return g[a][b];

return g[a][b] = g[b][a] = (b==0)?a:gcd(b,a%b);
}

int getnum()
{
int ans = 0;
char c = getchar();
while( !isdigit(c) ) c = getchar();

while( isdigit(c) )
{
ans = ans * 10 + c - '0';
c = getchar();
}
return ans;
}
int main()
{
Clean(g,-1);
T = getnum();
while(T--)
{
Clean(dp,0);
n = getnum();
int uplim = 0;
rep(i,1,n)
{
a[i] = getnum();
uplim = max(uplim,a[i]);
}
dp[1][a[1]] = 1;
rep(i,2,n)
{
dp[i][a[i]]++;
rep(j,1,uplim)
{
dp[i][gcd(a[i],j)]+=dp[i-1][j];
dp[i][gcd(a[i],j)]%=100000007;
dp[i][j]+=dp[i-1][j];//不选a[i]
dp[i][j]%=100000007;
}
}
LL ans = 0;
rep(i,1,uplim) ans=(ans+i*dp
[i])%100000007;
printf("%I64d\n",ans%100000007);
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: