Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 535 Accepted Submission(s): 188
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.
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].
1≤T≤50
題目大意:
給定一個序列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);
}
}