正题
题目链接:https://www.luogu.com.cn/problem/P6015?contestId=25945
题目大意
nnn张牌,玩家111从顶拿若干张,之后玩家222拿若干张。
若牌的和大于KKK那么分数为0否则为牌的和。
求KKK为多少时玩家111必胜。
解题思路
我们枚举玩家111拿多少张,然后用一个指针记录玩家222拿到哪里时比玩家111大。若玩家111的和为lll,玩家222刚好比玩家111拿的大时的和为rrr。
那么[l,r−1][l,r-1][l,r−1]这个范围都是可以选择的KKK,用树状数组区间覆盖即可。
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define lowbit(x) (x&-x)
using namespace std;
const ll N=1e6+10;
ll n,a[N],t[N],K,ans;
void Change(ll x,ll w){if(!x) return;while(x<=K){t[x]+=w;x+=lowbit(x);}return;
}
ll Ask(ll x){ll ans=0;while(x){ans+=t[x];x-=lowbit(x);}return ans;
}
int main()
{scanf("%lld",&n);for(ll i=1;i<=n;i++)scanf("%lld",&a[i]);scanf("%lld",&K);ll l=2,z=a[1],sum=0;for(ll i=1;i<=n;i++){sum+=a[i];z-=a[i];while(l<=n&&z<sum)z+=a[l++];if(sum<z){Change(sum,1);Change(z,-1);}if(z<sum)Change(sum,1);}for(ll i=1;i<=K;i++)if(Ask(i)) ans++;printf("%lld\n",ans);for(ll i=1;i<=K;i++)if(Ask(i)) printf("%lld ",i);
}