题目链接
首先猜一个结论:$\sum a_i\ge c\times s$就可行。
发现这个是显然错误的,因为有一些$a_i\ge s$,它们最多只有$c$的贡献。
那么把这些数去掉,相应地减少$c$的值,接下来呢?
我们发现这个结论成立了。
有两种思路:
我们把选数看作是填一个$c$列$s$行的表格,$i$可以填$a_i$次,限定同一下标不能填在同一行。因为$a_i<s$,所以直接依次按列填下去,一定不会冲突。这样下来“填满”也就是$\sum a_i\ge c\times s\Leftrightarrow$选数操作可行。
固定$\sum a_i$,当所有元素都是$s-1$时,元素个数最少,是$\lceil \dfrac{sum}{s-1}\rceil$个,且我们有$sum\ge c\times s$,那么$$\lceil\dfrac{sum}{s-1}\rceil\times (s-1)\ge sum\ge c\times s$$
$$\lceil \dfrac{sum}{s-1}\rceil \ge c\times\dfrac{s}{s-1}\ge c$$
发现一定有解。
那么接下来就是用数据结构维护前缀计数和以及前缀和了。我这里用的是离散化之后的树状数组。注意前缀和树状数组要存原始值的和用来相乘。
代码(100分):
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<queue> #include<map> #include<set> #define IL inline #define RG register #define _1 first #define _2 second using namespace std; typedef long long LL; const int N=1e6; int n,m,a[N+3]; struct Opt{ int t,k,x,r; }p[N+3]; int k,b[N+3]; IL int sol(int x){ int l=1,r=k,mid,ans; while(l<=r){ mid=(l+r)>>1; if(x<=b[mid]){ r=mid-1; ans=mid; } else l=mid+1; } return ans; } IL void discrete(){ for(int i=1;i<=m;i++) b[i]=p[i].x; sort(b+1,b+m+1); k=1; for(int i=2;i<=m;i++) if(b[i]!=b[i-1]) b[++k]=b[i]; for(int i=1;i<=m;i++) p[i].r=sol(p[i].x); } LL sc[N+3],sx[N+3]; IL int lowbit(int x){ return x&(-x); } IL void mdf(LL *s,int p,LL x){ for(;p<=k;p+=lowbit(p)) s[p]+=x; } IL LL qry(LL *s,int p){ LL ret=0; for(;p;p-=lowbit(p)) ret+=s[p]; return ret; } int c[N+3],x[N+3]; IL void dat_init(){ memset(c,0,sizeof 0); memset(sc,0,sizeof sc); memset(sx,0,sizeof sx); } int main(){ scanf("%d%d\n",&n,&m); for(int i=1;i<=m;i++){ char ch; scanf("%c %d %d\n",&ch,&p[i].k,&p[i].x); p[i].t=ch=='U'?1:2; } discrete(); dat_init(); for(int i=1;i<=m;i++) if(p[i].t==1){ if(c[p[i].k]!=0){ mdf(sc,c[p[i].k],-1); mdf(sx,c[p[i].k],-x[p[i].k]); } c[p[i].k]=p[i].r; x[p[i].k]=p[i].x; mdf(sc,c[p[i].k],1); mdf(sx,c[p[i].k],x[p[i].k]); } else { p[i].k-=qry(sc,k)-qry(sc,p[i].r-1); if(p[i].k<=0||qry(sx,p[i].r-1)>=1LL*p[i].k*p[i].x) printf("TAK\n"); else printf("NIE\n"); } return 0; }View Code