BestCoder Round #78 (div.2)


B:DP

题意:n个数中取若干数的GCD,求所有不同取法的GCD和。

分析:我们令dp[i][j]表示在前i个数中,选出若干个数使得它们的gcd为j的方案数,于是只需要枚举第i+1个数是否被选中来转移就可以了
令第i+1个数为v,当考虑dp[i][j]的时候,我们令dp[i+1][j] += dp[i][j]dp[i+1][j]+=dp[i][j](v 不选),dp[i+1][gcd(j,v)] += dp[i][j]dp[i+1][gcd(j,v)]+=dp[i][j](v 选)
复杂度O(N*MaxV) MaxV 为出现过的数的最大值

代码:

#include <algorithm>
#include <iostream>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <set>
#include <map>
#include <ctime>
#define INF 0x3f3f3f3f
#define Mn 1010
#define Mm 200010
#define mod 100000007
#define CLR(a,b) memset((a),(b),sizeof((a)))
#define CPY(a,b) memcpy ((a), (b), sizeof((a)))
#pragma comment(linker, "/STACK:102400000,102400000")
#define ul u<<1
#define ur (u<<1)|1
using namespace std;
typedef long long ll;
int dp[Mn][Mn];
int f[Mn][Mn];
int a[Mn];
int gcd(int a,int b) {
    return b==0?a:gcd(b,a%b);
}
int main()
{
    for(int i=1;i<=Mn;i++) 
        for(int j=1;j<=Mn;j++)
            f[i][j]=gcd(i,j);
    int t;
    cin>>t;
    while(t--) {
        int n;
        cin>>n;
        CLR(dp,0);
        for(int i=1;i<=n;i++) {
            scanf("%d",&a[i]);
            dp[i][a[i]]=1;
        }
        
        for(int i=1;i<n;i++) {
            for(int j=1;j<=Mn;j++) {
                (dp[i+1][j]+=dp[i][j])%=mod;
                (dp[i+1][f[a[i+1]][j]]+=dp[i][j])%=mod;
            }
        }
        int ans=0;
        for(int i=1;i<=Mn;i++){ 
            ans=(ans+(ll)i*dp[n][i]%mod)%mod;
            
        }       
        cout<<ans<<endl;    
    }
    return 0;
}


你可能感兴趣的:(BestCoder Round #78 (div.2))