云斗杯 T2 派蒙是最好的伙伴! 题解
云斗杯 T2 题解
赛时脑抽了只打了 60pts 暴力 xwx。
题目描述
给定两个长度为
现给定一个数
样例 #1
样例输入 #1
4 4 0 1 1 1 1 0 1 0
样例输出 #1
6
样例解释
如图,取蓝色字部分、米色背景部分、两个粗线框内部,以及小粗线框加上紫色或绿色的
数据范围
思路
首先看到
然后我们来考虑一个包含
那么,现在问题就转化为了求两个序列中,区间和为
代码:
#include<bits/stdc++.h> #define ll long long using namespace std; const int N = 3e5+100; const int mod = 998244353; inline ll read(){ ll x = 0; char ch = getchar(); while(ch<'0' || ch>'9') ch = getchar(); while(ch>='0'&&ch<='9') x = x*10+ch-48, ch = getchar(); return x; } int a[N], b[N]; ll sa[N], sb[N]; int n; ll K; ll fa[N], fb[N]; ll yin[10000], toty; int main(){ n = read(), K = read(); for(ll i = 1; i*i<=K; ++i){ if(K%i) continue; yin[++toty] = i; if(K/i!=i) yin[++toty] = K/i; } for(int i = 1; i<=n; ++i){ a[i] = read(); sa[i] = sa[i-1]+a[i]; } for(int i = 1; i<=n; ++i){ b[i] = read(); sb[i] = sb[i-1]+b[i]; } // for(int i = 1; i<=n; ++i){ // for(int j = 1; j<=i; ++j){ // ++fa[sa[i]-sa[j-1]]; // } // } // for(int i = 1; i<=n; ++i){ // for(int j = 1; j<=i; ++j){ // ++fb[sb[i]-sb[j-1]]; // } // }//暴力部分 xwx int ans = 0; for(ll i = 1; i<=toty; ++i){ ll yina = yin[i], yinb = K/yin[i]; if(yina > sa[n] || yinb > sb[n]) continue; ll tmpa = 0, tmpb = 0; for(int l = 1, r = 1, ta = 0, tb = 0; r<=n; ++r){ if(sa[r] < yina) continue; while(sa[r]-sa[l-1] > yina) ++l, ++ta; if(sa[r]!=sa[r-1]){ tmpa = (tmpa+1ll*ta*tb%mod)%mod; ta = 0, tb = 0; } ++tb; if(r == n){ while(sa[r]-sa[l-1] == yina) ++l, ++ta; tmpa = (tmpa+ta*tb%mod)%mod; } } for(int l = 1, r = 1, ta = 0, tb = 0; r<=n; ++r){ if(sb[r] < yinb) continue; while(sb[r]-sb[l-1] > yinb) ++l, ++ta; if(sb[r]!=sb[r-1]){ tmpb = (tmpb+ta*tb%mod)%mod; ta = 0, tb = 0; } ++tb; if(r == n){ while(sb[r]-sb[l-1] == yinb) ++l, ++ta; tmpb = (tmpb+1ll*ta*tb%mod)%mod; } } ans = (ans+1ll*tmpa*tmpb)%mod; } // for(int i = 1; i<=n; ++i){ // if(K%i) continue; // if(i>sa[n]) continue; // ll tmp = K/i; // if(tmp>sb[n]) continue; // ans = (1ll*ans+1ll*fa[i]*fb[tmp]%mod)%mod; // } printf("%d\n", ans); return 0; }