codeforces 992D:并查集

题意:

给一个数列,求出子区间个数,要求满足 rlai=Krlai ∏ 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;
}
### 关于Codeforces Educational Round 175的信息 对于特定编号的比赛如Codeforces Educational Round 175,官方通常会在比赛页面提供完整的题目列表以及对应的测试数据和解决方案。然而,在当前可访问的数据中并未直接提及此轮次的具体细节[^1]。 为了获取该轮赛事的问题集及其解答方案,建议访问Codeforces官方网站并导航至对应的比赛页面。每场比赛结束后,平台会发布一篇博客文章总结这场比赛的情况,其中包括解题思路、标准答案以及其他参赛者的高效实现方法[^2]。 此外,社区成员经常会在评论区分享个人见解与代码片段,这些资源同样有助于理解如何解决这些问题。值得注意的是,虽然这里提到的其他几场教育赛(例如第4轮、第22轮、第65轮)提供了关于输入格式等方面的描述,但对于具体到第175轮的内容,则需参照上述途径来获得最准确的信息[^3]。 ```python # 示例:查询指定比赛的方法 import requests def get_contest_info(contest_id): url = f"https://codeforces.com/api/contest.standings?contestId={contest_id}&from=1&count=1" response = requests.get(url).json() if 'result' not in response or 'problems' not in response['result']: return None problems = [] for prob in response['result']['problems']: problems.append({ 'index': prob['index'], 'name': prob['name'] }) return { 'id': contest_id, 'problems': problems } print(get_contest_info(175)) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值