CF 475D CGCDSSQ 解題報告(DP)

D. CGCDSSQ
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Given a sequence of integers a1, ..., an and q queries x1, ..., xq on it. For each query xi you have to count the number of pairs(l, r) such that 1 ≤ l ≤ r ≤ n and gcd(al, al + 1, ..., ar) = xi.

 is a greatest common divisor of v1, v2, ..., vn, that is equal to a largest positive integer that divides all vi.

Input

The first line of the input contains integer n, (1 ≤ n ≤ 105), denoting the length of the sequence. The next line contains nspace separated integers a1, ..., an, (1 ≤ ai ≤ 109).

The third line of the input contains integer q, (1 ≤ q ≤ 3 × 105), denoting the number of queries. Then follows q lines, each contain an integer xi, (1 ≤ xi ≤ 109).

Output

For each query print the result in a separate line.

Sample test(s)
input
3
2 6 3
5
1
2
3
4
6
output
1
2
2
0
1
input
7
10 20 3 15 1000 60 16
10
1
2
3
4
5
6
10
20
60
1000
output
14
0
2
2
2
0
2
2
1
1

    解題報告: 昨晚CF的D題。當時想枚舉起點,然後按照gcd的遞減,二分出相同gcd時的最大終點,計算段gcd時用線段樹。無奈超時……

    隊友DP出來了,利用的性質是一樣的。一段數長度越長,gcd越小,且嚴格單調遞減。因爲int類型在2^31以內,所以可以肯定一個數最多有31個gcd(每次減少至少一個素因子)。我們可以枚舉終點,當前的gcd數可以由上一次gcd的結果遞推出來。這樣問題就解決了。

    代碼如下(GNU C++0x 提交):

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <iomanip>
#include <cassert>
using namespace std;
#pragma comment(linker, "/STACK:1024000000,1024000000")
#define ff(i, n) for(int i=0;i<(n);i++)
#define fff(i, n, m) for(int i=(n);i<=(m);i++)
#define dff(i, n, m) for(int i=(n);i>=(m);i--)
#define travel(e, u) for(int e = u, v = vv[u]; e; e = nxt[e], v = vv[e])
#define bit(n) (1LL<<(n))
#define And(a, b) ((a) & (b))
#define Or(a, b) ((a) | (b))
#define Xor(a, b) ((a) ^ (b))
#define clr(a, b) memset((a), b, sizeof(a))
typedef long long LL;
typedef unsigned long long ULL;
void work();
int main()
{
#ifdef ACM
    freopen("in.txt", "r", stdin);
#endif // ACM

    work();
    return 0;
}

void scanf(int & x, char ch = 0)
{
    while((ch=getchar()) < '0' || ch > '9');

    x = ch - '0';
    while((ch=getchar()) >= '0' && ch <= '9') x = x * 10 + ch - '0';
}

/***************************************************************************************/

int gcd(int a, int b)
{
    if(a&&b) while(a>b?a=a%b:b=b%a);
    return a+b;
}

int a[111111];
int q[333333];

void work()
{
    int n, m;
    while(scanf("%d", &n) == 1)
    {
        fff(i, 1, n) scanf(a[i]);

        int m;
        scanf("%d", &m);
        ff(i, m) scanf(q[i]);

        map<int, LL> ans;
        map<int, int> dp[2];
        int now = 0, pre = 1;
        fff(i, 1, n)
        {
            swap(now, pre);
            dp[now].clear();

            dp[now][a[i]] = 1;
            for(auto it : dp[pre])
                dp[now][gcd(a[i], it.first)] += it.second;

            for(auto it : dp[now])
                ans[it.first] += it.second;
        }

        ff(i, m) if(ans.count(q[i]))
            printf("%I64d\n", ans[q[i]]);
        else
            puts("0");
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章