Codeforces Round #489 (Div. 2) ---- D - Nastya and a Game

参考了别人的博客,已注明为转载

这也是看了题解搞定的,这题很巧妙的利用了范围的问题,我们先略过所有是1的数,(a1 + .... + an) *k 这个的最大范围是 n*k*1e8  = 2e18,接近LL_MAX 的范围,那也就是说,对于至少为2的数来说,64个数相乘就能爆掉这个答案,因此答案连续的段去掉1之后,至多只可能有64个数,那么再考虑1,因为1对乘积没有影响,因此我们可以把连续的1看成是1段,然后判断通过对和加上这些1里面的部分数,能不能有符合答案的数,然后跳过这段1,这样保证在计算一段的时候,只计算至多64次

然后碰到的坑,LL 类型爆了貌似不会立刻小于0 ?特判是否爆LL 用 

if (mul > LLONG_MAX / a[j]) break;

然后没啥了,代码如下

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL gcd(LL a,LL b){if (b == 0) return a; return gcd(b , a%b);}
LL lcm(LL a,LL b){ return a/gcd(a,b)*b;}
inline int read(){
    int f = 1, x = 0;char ch = getchar();
    while (ch > '9' || ch < '0'){if (ch == '-')f = -f;ch = getchar();}
    while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x * f;
}
const int maxn = 2e5 + 10;
LL a[maxn],cnt[maxn];
int main(){
    int n,k;
    LL ans = 0;
    n = read(); k = read();
    for (int i=0; i<n; i++)
        a[i] = read();
    LL mul = 1,add = 0;
    for (int i=n-1; i>=1; i--) {
        if (a[i] == 1) cnt[i-1] = cnt[i] + 1;
    }
    for (int i=0; i<n; i++) {
        mul = 1; add = 0;
        for (int j=i; j<n; j++) {
            if (mul > LLONG_MAX / a[j]) break;
            mul *= a[j];
            add += a[j];
            if (mul == add*k) { ans++; }
            else{
                if (add*k < mul && mul % k == 0 && add + cnt[j] >= mul/k)
                    ans++;
                LL x = cnt[j];
                j += x;
                add += x;
            }
        }
    }
    cout << ans << endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/CCCCTong/article/details/82715565