【POI2015】LOG

题目链接

首先猜一个结论:$\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分):

【POI2015】LOG
#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

 

上一篇:List与表的连接查询


下一篇:杂题