codeforces 818E Card Game Again (尺取法)

来源:互联网 发布:linux 远程执行命令 编辑:程序博客网 时间:2024/05/29 19:05

题目原文:http://codeforces.com/contest/818/problem/E

E. Card Game Again

Vova again tries to play some computer card game.

The rules of deck creation in this game are simple. Vova is given an existing deck of n cards and a magic number k. The order of the cards in the deck is fixed. Each card has a number written on it; number ai is written on the i-th card in the deck.

After receiving the deck and the magic number, Vova removes x (possibly x = 0) cards from the top of the deck, y (possibly y = 0) cards from the bottom of the deck, and the rest of the deck is his new deck (Vova has to leave at least one card in the deck after removing cards). So Vova's new deck actually contains cards x + 1x + 2, ... n - y - 1n - y from the original deck.

Vova's new deck is considered valid iff the product of all numbers written on the cards in his new deck is divisible by k. So Vova received a deck (possibly not a valid one) and a number k, and now he wonders, how many ways are there to choose x and yso the deck he will get after removing x cards from the top and y cards from the bottom is valid?

Input

The first line contains two integers n and k (1 ≤ n ≤ 100 0001 ≤ k ≤ 109).

The second line contains n integers a1a2, ..., an (1 ≤ ai ≤ 109) — the numbers written on the cards.

Output

Print the number of ways to choose x and y so the resulting deck is valid.

Examples
input
3 46 2 8
output
4
input
3 69 1 14
output
1

题目大意:对给定的a数组,有多少个l,r区间可以满足其中所有元素的乘积一定能够整除k。

解题思路:

因为答案有一定的延续性(对每个i,如果i-j满足条件,右端点可以取到j后面所有的位置),可以使用尺取法解决这个问题。

然后需要解决的问题就是怎么维护出k的倍数这个条件,最开始只是简单选择了gcd方法,但是通过样例发现了这个方法的bug,所以我们需要对k质因数分解,同时对每个a[i]进行关于k质因子的分解。从而可以判断一段区间能否整除k。

AC代码:

/*    @Author: wchhlbt    @Date:   2017/8/2*/#include <bits/stdc++.h>#define Fori(x) for(int i=0;i<x;i++)#define Forj(x) for(int j=0;j<x;j++)#define maxn 100007#define inf 0x3f3f3f3f#define ONES(x) __builtin_popcount(x)#define _  << "  " <<using namespace std;typedef long long ll ;const double eps =1e-8;const int mod = 1000000007;typedef pair<int, int> P;const double PI = acos(-1.0);int dx[4] = {0,0,1,-1};int dy[4] = {1,-1,0,0};inline int read(){ int num;    scanf("%d",&num);   return num;}int p,n;int a[maxn];ll ans;int prime[50];//从1开始编号int pcnt[50];int b[maxn][50];int c[50];int main(){    //freopen("test.txt","r",stdin);    //cout << gcd(4,14) << endl;    int n = read();    int k = read();    int cnt = 0;    for(int i = 2; i<=sqrt(k); i++){//对K质因数分解        if(k%i==0){            prime[++cnt] = i;            while(k%i==0){                k /= i;                pcnt[cnt]++;            }        }    }    if(k>1){        prime[++cnt] = k;        pcnt[cnt] = 1;    }    for(int i = 1; i<=n; i++){        a[i] = read();        for(int j = 1; j<=cnt; j++){//对a[i]进行关于k质因子的分解            while(a[i]%prime[j]==0){                b[i][j]++;                a[i] /= prime[j];            }        }    }    int i = 1,j = 0;    while(i<=n){        int flag = false;        while(j<=n && !flag){            j++;            flag = true;            for(int w = 1; w<=cnt; w++){                c[w] += b[j][w];                flag &= (c[w]>=pcnt[w]);            }        }        if(!flag)   break;        while(flag && i<=j){//pay attention j should be greater than i            ans += n-j+1;            for(int w = 1; w<=cnt; w++){                c[w] -= b[i][w];                flag &= (c[w]>=pcnt[w]);            }            i++;        }    }    cout << ans << endl;    return 0;}/*尺取法int i = 1,j = 0;while(i<=n){    while(j<=n && 条件不满足){        j++;        条件修改           }    if(不满足条件)   break;    while(条件满足 && i<=j){        维护答案        进行条件修改        i++;    }}*/



原创粉丝点击