codeforces 992D:并查集

题意:

给一个数列,求出子区间个数,要求满足 l r a i = K l r a i
数据范围:
1<=n<=2e5
1<=K<=1e5
1<=ai<=1e8

题解:

数据范围已经安排好了算法。计算等式右端的最大值:1e5*2e5*1e8=2e18。嗯LL刚好。
假如说有ai>=2,那么直接暴力即可,因为左端是一个乘积,最多乘log2e18个数字就比右端大了。复杂度64n左右。
那么有连续的ai=1,则可以将他们并作一段,观察等式左边增加一个1,值不变,右边增加一个1,值增大K。于是对于连续的一段1,可以直接O1做一次check,其他情况依旧暴力。只是常数大了一倍左右。

Attention:

判断 a * b 是否溢出:

inline bool overflow_LL(LL a,LL b){
    return a>LLONG_MAX/b;
}
//C++14不可用,a*b/b会被优化成a,C++11/17的O(1-3)均不会进行优化。
inline bool overflow_LL(LL a,LL b){
    return a*b/b!=a;
}
//通过volatile拒绝编译器优化,可以避免上面的问题
inline bool overflow_LL(LL a,LL b){
    volatile LL c = a*b;
    return c/b!=a;
}

不信的话。。可以尝试一下第二种溢出方式。。。然后你会认识132号数据点。

Code:

//
// Created by calabash_boy on 18-6-19.
//
#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
typedef long long LL;
const int MOD = 1e9+7;const int maxn =2e5+100;
typedef long double db;
LL a[maxn];
LL n,K;
LL sum=0;
int fa[maxn];
int find(int x){
    return fa[x]==x?x:fa[x] = find(fa[x]);
}
inline bool overflow_LL(LL a,LL b){
    return a>LLONG_MAX/b;
}
void input(){
    scanf("%I64d%I64d",&n,&K);
    for (int i=1;i<=n;i++){
        scanf("%I64d",a+i);
        fa[i]=i;
        sum+=a[i];
    }
    sum*=K;
}
void solve(){
    for (int i=1;i<n;i++){
        if(a[i]==1&&a[i+1]==1){
            fa[find(i)] = find(i+1);
        }
    }
    LL ans =0;
    for (int i=1;i<=n;i++){
        LL tempSum =K*a[i];
        LL tempPro =a[i];
        int j=i;
        do{
            if(tempSum==tempPro)ans++;
            j++;
            if(j>n)break;
            if(find(j)==j){
                tempSum+=K*a[j];
                if(overflow_LL(tempPro,a[j]))break;
                tempPro*=a[j];
            }else{
                int k = find(j);
                LL l = tempSum+K;
                LL r = tempSum+1LL*K*(k-j+1);
                if(l<=tempPro&&tempPro<=r&&(tempPro-tempSum)%K==0){
                    int delta = (tempPro-tempSum)/K-1;
                    j +=delta;
                    tempSum=tempPro;
                }else{
                    tempSum+=K*(k-j+1);
                    j = find(j);
                }
            }
        }while (tempPro<=sum&&j<=n);
    }
    cout<<ans<<endl;
}
int main(){
    input();
    solve();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/calabash_boy/article/details/80728058
今日推荐