您的位置:首页 > 其它

HDU - CA Loves GCD

2016-04-03 20:46 288 查看

1.题面

http://acm.hdu.edu.cn/showproblem.php?pid=5656

2.题意

给你一堆数,对于这堆数的所有组合,(如{1,2},有{1},{2},{1,2}三种组合)求出所有组合的最大公约数之和。

3.解题思路

用动态规划做,用dp[i][j]表示已经选择了i个数,其中最大公约数为j的数字有dp[i][j]个。

则dp[i+1][j]包含所有dp[i][j]的组合,同时需要加入所有前面的组合与加入j以后的情况。

设置dp[0][0] = 1;

为初始情况,那么每次添加i时i与i的gcd情况都可以通过i与0的gcd来添加一个dp[i][num[i]]++;

简直妙手!

具体的看代码,我用了滚动数组。

4.解题代码

/*****************************************************************
> File Name: tmp.cpp
> Author: Uncle_Sugar
> Mail: uncle_sugar@qq.com
> Created Time: 2016年04月02日 星期六 19时42分02秒
*****************************************************************/
# include <cstdio>
# include <cstring>
# include <cmath>
# include <cstdlib>
# include <climits>
# include <iostream>
# include <iomanip>
# include <set>
# include <map>
# include <vector>
# include <stack>
# include <queue>
# include <algorithm>
using namespace std;

const int debug = 0;
const int size  = 1000 + 10;
const int INF = INT_MAX>>1;
const int MOD = 100000007;
typedef long long ll;

int gcd[size][size];
int getGcd(int x,int y){
if (gcd[x][y]==0){
gcd[y][x] = gcd[x][y] = (y==0?x:getGcd(y,x%y));
}
return gcd[x][y];
}
int num[size];
int dp1[size];
int dp2[size];
int main()
{
std::ios::sync_with_stdio(false);cin.tie(0);
int i,j;
int T;
cin >> T;
while (T--){
int n;
cin >> n;
int maxsum = -1;
for (i=0;i<n;i++){
cin >> num[i];
maxsum = max(maxsum,num[i]);
}
int *guest = dp1;
int *host = dp2;
int *tmp;
memset(host,0,sizeof(int)*size);
host[0] = 1;
for (i=0;i<n;i++){
for (j=0;j<=maxsum;j++)
guest[j] = host[j];
for (j=0;j<=maxsum;j++){
if (host[j]>0){
int G = getGcd(j,num[i]);
guest[G] += host[j];
guest[G] %= MOD;
}
}
tmp = guest;guest = host;host = tmp;
}
ll ans = 0;
for (i=0;i<=maxsum;i++){
ans += (ll)host[i]*i;
ans %= MOD;
}
cout << ans << '\n';
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: