【题目】
2017: 开心的cc
Time Limit: 1 Sec Memory Limit: 128 MB
Submit: 246 Solved: 73
[Submit][Status][Web Board]
Description
Input
1<=T<=20,1<=N<=100000
Output
Output a integer represents the answer
Sample Input
2
5
1 0 1 1 0
5
1 1 1 1 1
Sample Output
1
5
HINT
【题解】
题意:给你一段最小周期,以第i天为起始点顺延n天,每天累计的1的个数均大于0的个数,问这样的i有多少个。
1.思维 2.线段树
【思维】
#include<stdio.h>
#include<string.h>
#define mem(x) memset(x,0,sizeof(x));
int main()
{
int i,j,m,n,t;
int a[100005],b[100005],c[100005];
scanf("%d",&t);
while(t--)
{
int qum=100001,sum=0;
mem(b) mem(c)
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
if(a[i]==0)
sum--;
else
sum++;
b[i]=sum; //做一次前缀和操作,01相抵消
}
for(i=1;i<=n;i++)
{
if(b[i]<qum)
qum=b[i];
else
b[i]=qum; //后半段i到n所需要被贡献的1的个数,最小值为1
}
sum=0;
for(i=n;i>=1;i--)
{
if(a[i]==1)
sum++;
else
sum--;
c[i]=sum; //代表后半段从i开始到n所能剩下的1的个数,即能为前半段贡献1的个数
}
sum=0,qum=0;
for(i=n;i>=1;i--)
{
if(a[i]==1)
sum++;
else
sum--;
if(sum>0) //如果sum大于0,则满足后半段,需要判前半段
{
if(c[i]+b[i-1]>0) //后半段所能贡献的1的个数贡献给前半段
qum++;
sum=0;
}
}
printf("%d\n",qum);
}
return 0;
}
【线段树】
#include<bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=200010;
int a[maxn];
int sum[maxn];
int c[4*maxn];
void build(int l,int r,int rt)
{
if(l==r)
{
c[rt]=sum[l];
return;
}
int mid=(l+r)/2;
build(l,mid,2*rt);
build(mid+1,r,2*rt+1);
c[rt]=min(c[2*rt],c[2*rt+1]);
}
int query(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R) return c[rt];
int mid=(l+r)/2;
int left=inf,right=inf;
if(L<=mid)
left=query(L,R,l,mid,2*rt);
if(R>mid)
right=query(L,R,mid+1,r,2*rt+1);
return min(left,right);
}
main()
{
int t,n;
scanf("%d",&t);
while(t--)
{
memset(sum,0,sizeof(sum));
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
if(a[i]==0) a[i]=-1;
a[i+n]=a[i];
}
int ans=0;
for(int i=1;i<=2*n;i++)
sum[i]=sum[i-1]+a[i];
build(1,2*n,1);
for(int i=1;i<=n;i++)
if(query(i,i+n-1,1,2*n,1)>sum[i-1])
ans++;
printf("%d\n",ans);
}
}