简单的平衡规划题目。
注意到“倍数”的限制,这很平衡规划。我们设限制为 。若直接枚举 ,条件为 ,条件即为 ,开个桶记录一下,再扫一遍即可。这个做法时间复杂度为 。这是对于 较小的做法。
考虑 的答案,直接暴力枚举起点 ,将 的点串在一起,这样对于每个 最多会跳 次。过程中我们直接统计长度为 的倍数的个数。
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #define ll long long using namespace std; const int N=2e5+10,M=1e7+10; template<class T> inline void read(T &x) { x=0;bool f=0; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=getchar();} while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); if(f)x=~x+1; } template<class T,class ...T1> inline void read(T &x,T1 &...x1) { read(x),read(x1...); } int n,B; char s[N]; int pre[N],sum[M<<1]; int ne[N]; ll ans; int main() { scanf("%s",s+1); n=strlen(s+1); B=sqrt(n)+1; s[0]='0'; for(int i=1;i<=n;i++)pre[i]=pre[i-1]+(s[i]=='1'); for(int i=1;i<=B;i++) { memset(sum,0,sizeof(sum)); for(int j=0;j<=n;j++) { int now=i*pre[j]-j+M; ans+=sum[now]; sum[now]++; } } int pos=n+1; for(int i=n;~i;i--) { ne[i]=pos; if(s[i]=='1')pos=i; } for(int i=0;i<n;i++) { int l=i,r=ne[i]; for(int j=1;j<=n/B&&j<=pre[n]-pre[i];j++) { l=ne[l],r=ne[r]; int resl=max(l-i-1,j*B),resr=r-i-1; if(resl<resr)ans+=resr/j-resl/j; } } printf("%lld",ans); return 0; }
|
Gitalk 加载中 ...