NOI2017 部分题解

D1

T1
模拟一个很大的二进制加减法
压位线段树,每个位置压二进制的30位,每次修改涉及1~2个位置,分别修改
对于一个位置i +/-,至多产生1个进/退位,相当于在i+1~inf +/- 1,找到>=i的位置中最小的非1/0位,中间的全部改0/1,这一位+/-1

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;

inline void read(int &x)
{
    char c; int f=1; while(!((c=getchar())>='0'&&c<='9')) if(c=='-') f=-f;
    x=c-'0';
    while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';
    x*=f;
}
const int maxn = 2100000;

int n,m;
int seg[maxn<<2];
void pushdown(const int x) { if(seg[x]!=-1) seg[x<<1]=seg[x<<1|1]=seg[x]; }
void pushup(const int x) { seg[x]=seg[x<<1]==seg[x<<1|1]?seg[x<<1]:-1; }

int loc;
int search(const int x,const int l,const int r)
{
    if(l==r) return x;
    pushdown(x);
    int mid=l+r>>1;
    if(loc<=mid) search(x<<1,l,mid);
    else search(x<<1|1,mid+1,r);
}
int lx,rx,c;
int find0(const int x,const int l,const int r)
{
    if(r<lx||seg[x]==(1<<30)-1) return -1;
    if(l==r) { seg[x]++; rx=r-1; return 1; }
    pushdown(x);
    int mid=l+r>>1;
    int re=find0(x<<1,l,mid);
    if(re!=-1) { pushup(x); return re; }
    re=find0(x<<1|1,mid+1,r); pushup(x); 
    return re;
}
int find1(const int x,const int l,const int r)
{
    if(r<lx||seg[x]==0) return -1;
    if(l==r) { seg[x]--; rx=r-1; return 1; }
    pushdown(x);
    int mid=l+r>>1;
    int re=find1(x<<1,l,mid);
    if(re!=-1) { pushup(x); return re; }
    re=find1(x<<1|1,mid+1,r); pushup(x);
    return re;
}
void upd(const int x,const int l,const int r)
{
    if(rx<l||r<lx) return;
    if(lx<=l&&r<=rx) { seg[x]=c; return; }
    pushdown(x);
    int mid=l+r>>1;
    upd(x<<1,l,mid); upd(x<<1|1,mid+1,r);
    pushup(x);
}
void add(const int k,const int v)
{
    loc=k; int x=search(1,0,n);
    seg[x]+=v; int ci=seg[x]>=(1<<30)?1:0;
    seg[x]&=(1<<30)-1;
    while(x) x>>=1,pushup(x);

    if(ci)
    {
        lx=k+1; find0(1,0,n);
        c=0; if(lx<=rx) upd(1,0,n);
    }
}
void dec(const int k,const int v)
{
    loc=k; int x=search(1,0,n);
    seg[x]-=v; int ci=seg[x]<0?1:0;
    if(seg[x]<0) seg[x]+=1<<30;
    while(x) x>>=1,pushup(x);

    if(ci)
    {
        lx=k+1; find1(1,0,n);
        c=(1<<30)-1; if(lx<=rx) upd(1,0,n);
    }
}
int query(const int k)
{
    loc=k/30; int x=search(1,0,n);
    return seg[x]>>k-loc*30&1;
}

int main()
{
    scanf("%d%*d%*d%*d",&m); n=m+2;
    while(m--)
    {
        int t,x,y; read(t);
        if(t==1)
        {
            read(x); read(y);
            int sig=1; if(x<0) sig=-1,x=-x;

            int d=y/30*30,u=d+30;
            int cc=0;
            for(int i=0;i<30&&y+i<u;i++) if(x>>i&1) cc|=1<<i+y-d;
            if(cc) 
            {
                if(sig==1) add(d/30,cc);
                else dec(d/30,cc);
            }

            cc=0;
            for(int i=u-y;i<30;i++) if(x>>i&1) cc|=1<<i-(u-y);
            if(cc) 
            {
                if(sig==1) add(u/30,cc);
                else dec(u/30,cc);
            }
        }
        else read(x),printf("%d\n",query(x));
    }

    return 0;
}

T2
我没过这题…卡常卡了一个上午没卡过去…深深的怨念
因为询问的字串长度k<=50,实际上我们只关心长度<=k的串的出现次数,每次合并/分开两个串,至多影响k^2个串的出现次数
所以离线,hash表维护询问的所有子串的出现次数,双hash

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;

inline void read(int &x)
{
    char c; while(!((c=getchar())>='0'&&c<='9'));
    x=c-'0';
    while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';
}
int oo[10],on;
inline void output(int x)
{
    if(!x) { puts("0");return; }
    while(x)
    {
        int y=x/10; oo[++on]=x-y*10;
        x=y;
    }
    while(on) putchar('0'+oo[on--]);
    putchar('\n');
}
const int hash1 = 23333333;
//const int hash2 = 1e8+7;
const int Mod = 998244353;

const int maxk = 51;
const int maxn = 210000;
const int maxm = 510000;
const int maxs = 1e7+10;

int ph1[maxk+10],ph2[maxk+10];
int s1[maxs],s2[maxs];
void gethash(int x,int y,int &h1,int &h2)
{
    h1=(s1[y]-(ll)s1[x-1]*ph1[y-(x-1)]%hash1+hash1)%hash1;
    h2=s2[y]-(ll)s2[x-1]*ph2[y-(x-1)];
}
struct edge{int y,c;};
vector<edge>V[hash1]; int sum[maxk];
int fi(int h1,int h2)
{
    for(int j=0;j<V[h1].size();j++)
        if(V[h1][j].y==h2) return V[h1][j].c;
}
void ins(int h1,int h2) 
{
    for(int j=0;j<V[h1].size();j++) if(V[h1][j].y==h2) return;
    V[h1].push_back((edge){h2,0});
}
void upd(int h1,int h2,int c)
{
    for(int j=0;j<V[h1].size();j++)
        if(V[h1][j].y==h2) { V[h1][j].c+=c; return; }
}

int n,m;
struct list{int l,r,x;}a[maxn];
int temp[maxk<<2],L,R;

void link(const int x,const int y)
{
    int nowi=x; for(L=maxk;nowi&&maxk-L+1<50;L--,nowi=a[nowi].l) temp[L]=a[nowi].x; L++;
    nowi=y; for(R=maxk+1;nowi&&R-maxk<50;R++,nowi=a[nowi].r) temp[R]=a[nowi].x; R--;

    s1[L-1]=s2[L-1]=0;
    for(int i=L;i<=R;i++) 
    {
        s1[i]=s1[i-1]*11+temp[i]; if(s1[i]>=hash1) s1[i]%=hash1;
        s2[i]=s2[i-1]*23+temp[i];
    }
    for(int l=2;l<maxk;l++) if(sum[l])
    {
        for(int i=max(maxk+2-l,L);i<=maxk&&i+l-1<=R;i++)
        {
            int h1,h2; gethash(i,i+l-1,h1,h2);
            upd(h1,h2,1);
        }
    }
    a[x].r=y; a[y].l=x;
}
void cut(const int x)
{
    int y=a[x].r;
    int nowi=x; for(L=maxk;nowi&&maxk-L+1<50;L--,nowi=a[nowi].l) temp[L]=a[nowi].x; L++;
    nowi=y; for(R=maxk+1;R-maxk<50&&nowi;R++,nowi=a[nowi].r) temp[R]=a[nowi].x; R--;

    s1[L-1]=s2[L-1]=0;
    for(int i=L;i<=R;i++)
    {
        s1[i]=s1[i-1]*11+temp[i]; if(s1[i]>=hash1) s1[i]%=hash1;
        s2[i]=s2[i-1]*23+temp[i];
    }
    for(int l=2;l<maxk;l++) if(sum[l])
    {
        for(int i=max(maxk+2-l,L);i<=maxk&&i+l-1<=R;i++)
        {
            int h1,h2; gethash(i,i+l-1,h1,h2);
            upd(h1,h2,-1);
        }
    }
    a[x].r=0; a[y].l=0;
}

char str[maxs];
int e[maxm][3];
struct node{int h1,h2;};
vector<node>q[maxm];

int main()
{
    ph1[0]=ph2[0]=1;
    for(int i=1;i<maxk+10;i++) ph1[i]=(ll)ph1[i-1]*11%hash1,ph2[i]=(ll)ph2[i-1]*23;

    read(n); read(m);
    for(int i=1;i<=n;i++) read(a[i].x),a[i].l=a[i].r=0;
    for(int i=1;i<=m;i++)
    {
        int t; read(t);
        if(t==1) e[i][0]=1,read(e[i][1]),read(e[i][2]);
        else if(t==2) e[i][0]=2,read(e[i][1]);
        else
        {
            e[i][0]=3;
            scanf("%s",str+1); int len=strlen(str+1);
            int k; read(k); sum[e[i][1]=k]=1;
            int ss00=0,ss01=0,ss10=0,ss11=0;
            for(int j=1;j<=k;j++)
            {
                ss01=ss01*11+str[j]-48; if(ss01>=hash1) ss01%=hash1;
                ss11=ss11*23+str[j]-48;
            }
            for(int j=1;j+k-1<=len;j++)
            {
                int h1=(ss01-(ll)ss00*ph1[k]%hash1+hash1)%hash1;
                int h2=ss11-ss10*ph2[k];
                q[i].push_back((node){h1,h2});
                ins(h1,h2);

                ss00=ss00*11+str[j]-48; if(ss00>=hash1) ss00%=hash1;
                ss01=ss01*11+str[j+k]-48; if(ss01>=hash1) ss01%=hash1;
                ss10=ss10*23+str[j]-48;
                ss11=ss11*23+str[j+k]-48;
            }
        }
    }
    for(int i=1;i<=n;i++) upd(a[i].x,a[i].x,1);
    for(int i=1;i<=m;i++)
    {
        if(e[i][0]==1) link(e[i][1],e[i][2]);
        else if(e[i][0]==2) cut(e[i][1]);
        else
        {
            int re=1;
            for(int j=0;j<q[i].size();j++)
                re=(ll)re*fi(q[i][j].h1,q[i][j].h2)%Mod;
            output(re);
        }
    }

    return 0;
}

T3
令f[i][j]表示宽为j的矩形,下i行保证合法,i+1行存在不合法,这个矩形合法的概率
有f[i][j]=sigma p*f[>i][u]*f[>=i][j-u-1] (枚举不合法的位置,p是前i行合法i+1行不合法的概率)

当i>0时,因为i*j<=K,所以状态数是K的,暴力转移是K^2的,可以通过
当i=0时,设计另一个dp,g[i]表示前i个格子的答案,枚举连续的一段f[1]更新,因为中间要用不合法分开不是很方便转移,不妨令N=n+1,每次在末尾放一个不合法和一段f[1],f[N]/(不合法的概率)即答案
令p为一个格子合法的概率
此时g[i]=sigma g[i-j-1]*(1-p) *f[>=1][j], (j=0 to k)
化成一个常系数齐次递推式: g[i]=g[i-j]*a[j] (j=1 to k+1)
k<=100时可以直接矩乘
对于更大的数据,考虑优化这个东西
然后叉姐写过一个东西 《矩阵乘法递推的优化》 (好像是叫这个
然后学过线性代数的同学还是比较容易看懂的? (看不懂怎么办我怎么知道我也没看懂啊
弄出这个转移矩阵的特征多项式,快速幂求 x^n mod 这个特征多项式 就可以得到答案了

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define __ %=Mod
using namespace std;

const ll Mod = 998244353;
const int maxn = 2100;

ll pw(ll x,int k)
{
    ll re=1ll;
    for(;k;k>>=1,x=x*x%Mod) if(k&1)
        re=re*x%Mod;
    return re;
}
ll inv(ll x){return pw(x,Mod-2);}

ll temp[maxn];
void sqr(ll f[],int &len)
{
    int ren=len*2;
    for(int i=0;i<=len;i++) temp[i]=f[i];
    for(int i=0;i<=ren;i++) f[i]=0;
    for(int i=0;i<=len;i++)
    {
        for(int j=0;j<=len;j++)
            (f[i+j]+=temp[i]*temp[j]%Mod)__;
    }
    len=ren;
}
void mod(ll A[],int &an,ll B[],int bn)
{
    while(an>=bn)
    {
        int dec=an-bn;
        ll div=A[an]*inv(B[bn]);
        for(int j=0;j<=bn;j++) (A[j+dec]-=B[j]*div%Mod)__;
        while(!A[an]&&an) an--;
    }
}

int n,K; ll p,pi[maxn];
ll f[maxn][maxn],g[maxn][maxn],h[maxn];
ll a[maxn]; int an;
ll s[maxn]; int sn;
int t[maxn],tp;
ll cal()
{
    if(!K) return (pw(1-p,n)*inv(1-p)%Mod+Mod)%Mod;
    memset(f,0,sizeof f); 
    memset(g,0,sizeof g);

    pi[0]=1ll; for(int i=1;i<=K;i++) pi[i]=pi[i-1]*p%Mod;
    for(int i=K;i>=1;i--)
    {
        for(int j=1;i*j<=K;j++)
        {
            ll pp=(pi[i]*(1ll-p)%Mod+Mod)%Mod;
            for(int k=1;k<=j;k++)
            {
                ll t1=(k-1)?g[i+1][k-1]:1;
                ll t2=(k<j)?g[i][j-k]:1;
                (f[i][j]+=t1*t2%Mod*pp%Mod)__;
            }
            g[i][j]=(g[i+1][j]+f[i][j])%Mod;
        }
    }
    g[1][0]=1ll;
    //memset(h,0,sizeof h);
    h[0]=1;
    for(int i=K;i>=0;i--) g[1][i+1]=g[1][i]*(1ll-p)%Mod;
    for(int i=1;i<=K+1;i++)
    {
        h[i]=0;
        for(int j=0;j<i;j++) if(i-j<=K+1) (h[i]+=h[j]*g[1][i-j]%Mod)__;
    }
    //h[i]=h[i-j-1]*(1-p)*g[1][j]     j=0 to k
    //h[k+1]=sigma (1-p)*h[i]*g[1][k-i]
    //x^k+1-sigma (1-p)*g[1][k-i]*x^i=0;


    an=K+2; a[K+2]=1ll;
    for(int i=1;i<=K+1;i++) a[i]=-g[1][K+2-i];

    memset(s,0,sizeof s);
    sn=1; s[1]=1;
    tp=0; for(int now=n;now;t[tp++]=now&1,now>>=1);
    for(int i=tp-2;i>=0;i--)
    {
        sqr(s,sn); 
        if(t[i]) 
        {
            sn++;
            for(int i=sn;i>=1;i--) s[i]=s[i-1];
            s[0]=0;
        }
        mod(s,sn,a,an);
    }
    ll re=0ll;
    for(int i=0;i<=sn;i++) (re+=s[i]*h[i]%Mod)__;
    return (re*inv(1-p)%Mod+Mod)%Mod;
}

int main()
{
    int x,y; scanf("%d%d%d%d",&n,&K,&x,&y); ++n;
    p=(ll)x*inv(y)%Mod;
    ll ans1=cal(); K--;
    ll ans2=cal();
    printf("%lld\n",(ans1-ans2+Mod)%Mod);

    return 0;
}

D2

T1
不考虑有三种选择的d个地图,就是裸的2SAT,因为d很小,这d个点其实只有不选A,不选B两种选择(不需要再枚举不选C因为前两种可以覆盖所有合法情况)
可以2^d枚举d个地图不选哪个图,然后跑tarjan的2SAT
跑满了会T,所以还要加玄学剪枝和随机优化….

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define id(x,y) x*3-3+y
using namespace std;

inline void read(int &x)
{
    char c; while(!((c=getchar())>='0'&&c<='9'));
    x=c-'0';
    while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';
}
inline void down(int &x,const int &y){if(x>y)x=y;}
const int maxn = 310000;
const int maxm = 210000;

int n,m,d;
int pos[maxn],pn;
struct edge{int y,nex;}a[maxm]; int len,fir[maxn];
inline void ins(const int x,const int y){a[++len]=(edge){y,fir[x]};fir[x]=len;}

int dfn[maxn],low[maxn],id;
int t[maxn],tp; bool insta[maxn];
int bel[maxn],cnt;
void tarjan(const int x)
{
    dfn[x]=low[x]=++id; insta[t[++tp]=x]=true;
    for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y)
    {
        if(!dfn[y]) tarjan(y),down(low[x],low[y]);
        else if(insta[y]) down(low[x],dfn[y]);
    }
    if(low[x]==dfn[x])
    {
        ++cnt;
        int la=-1;
        while(la!=x)
        {
            insta[la=t[tp--]]=false;
            bel[la]=cnt;
        }
    }
}

char str[maxn];
int e[maxm][4],oth[maxn];
bool v[maxn];
int chosen[maxn],times;
bool judge()
{
    times++;
    len=0; for(int i=0;i<3*n;i++) fir[i]=0;
    for(int i=1;i<=m;i++)
    {
        int x=e[i][0],y=e[i][2];
        if(v[id(x,e[i][1])])
        {
            if(!v[id(y,e[i][3])]) { x=id(x,e[i][1]); ins(x,oth[x]); continue; }
            x=id(x,e[i][1]),y=id(y,e[i][3]);
            ins(x,y);
            ins(oth[y],oth[x]);
        }
    }
    id=cnt=0; for(int i=0;i<3*n;i++) dfn[i]=low[i]=bel[i]=0,insta[i]=false;
    tp=0; for(int i=0;i<3*n;i++) if(v[i]&&!dfn[i]) tarjan(i);

    for(int i=1;i<=n;i++)
    {
        int x=v[id(i,0)]?id(i,0):id(i,1);
        int y=oth[x];
        if(bel[x]==bel[y]) return false;
        chosen[i]=bel[x]<bel[y]?0:1;
    }
    return true;
}
bool solve(const int now)
{
    if(now>d)
    {
        if(judge()) return true;
        return false;
    }
    int k=pos[now];
    if(times>180) return false;
    if(rand()&1)
    {
        v[id(k,0)]=v[id(k,1)]=true; oth[id(k,0)]=id(k,1); oth[id(k,1)]=id(k,0);
        v[id(k,2)]=false;
        if(solve(now+1)) return true;
        v[id(k,0)]=v[id(k,2)]=true; oth[id(k,0)]=id(k,2); oth[id(k,2)]=id(k,0);
        v[id(k,1)]=false;
        return solve(now+1);
    }
    else
    {
        v[id(k,0)]=v[id(k,2)]=true; oth[id(k,0)]=id(k,2); oth[id(k,2)]=id(k,0);
        v[id(k,1)]=false;
        if(solve(now+1)) return true;
        v[id(k,0)]=v[id(k,1)]=true; oth[id(k,0)]=id(k,1); oth[id(k,1)]=id(k,0);
        v[id(k,2)]=false;
        return solve(now+1);
    }
}

char ss;

int main()
{
    srand(333333);

    read(n); read(d);
    scanf("%s",str);
    memset(v,true,sizeof v);
    for(int i=1;i<=n;i++) 
    {
        if(str[i-1]=='x') pos[++pn]=i;
        else
        {
            int x,y;
            if(str[i-1]=='a') x=id(i,1),y=id(i,2),v[id(i,0)]=false;
            else if(str[i-1]=='b') x=id(i,0),y=id(i,2),v[id(i,1)]=false;
            else x=id(i,0),y=id(i,1),v[id(i,2)]=false;
            oth[x]=y,oth[y]=x;
        }
    }

    read(m);
    for(int i=1;i<=m;i++)
    {
        read(e[i][0]); ss=getchar(); e[i][1]=ss-'A';
        read(e[i][2]); ss=getchar(); e[i][3]=ss-'A';
    }
    if(!solve(1)) return puts("-1"),0;
    for(int i=1;i<=n;i++)
    {
        int x=v[id(i,0)]?id(i,0):id(i,1),d=id(i,0);
        printf("%c",'A'+(chosen[i]==0?x-d:oth[x]-d));
    }

    return 0;
}

T2
有一个不难发现的性质:i天的最优答案选的蔬菜集合一定是i+1天选的蔬菜集合的子集
正解的实质就是模拟费用流过程并用数据结构优化
这题判一种选法是否合法,就是对于任意的t,保质期<=t的蔬菜数<=m*t,用f[n]表示保质期在<=n的蔬菜数,g[n]=f[n]-n*m,当 max g[n] <=0时合法即所有蔬菜都能被卖出
从第1天递推到第n天,维护一个每种蔬菜的大根堆,贪心的从堆顶依次取m个出来,每种取出其剩余保质期最大的,线段树对 [ 保质期,inf ]+1 ,判序列是否合法,不合法就撤销操作,否则选上这个蔬菜

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;

const int maxn = 210000;

int n,m,u,K;
int a[maxn],s[maxn],ci[maxn],xi[maxn];
struct segment
{
    int flag,mx;
}seg[maxn<<2];
void pushdown(const int x)
{
    int lc=x<<1,rc=lc|1;
    if(seg[x].flag)
    {
        int fl=seg[x].flag; seg[x].flag=0;
        seg[lc].flag+=fl; seg[lc].mx+=fl;
        seg[rc].flag+=fl; seg[rc].mx+=fl;
    }
}
void pushup(const int x) { seg[x].mx=max(seg[x<<1].mx,seg[x<<1|1].mx); }
void build(const int x,const int l,const int r)
{
    if(l==r) { seg[x].mx=-l*m; return; }
    int mid=l+r>>1,lc=x<<1,rc=lc|1;
    build(lc,l,mid); build(rc,mid+1,r);
    pushup(x);
}
int lx,rx,cc;
void upd(const int x,const int l,const int r)
{
    if(rx<l||r<lx) return;
    if(lx<=l&&r<=rx) { seg[x].flag+=cc; seg[x].mx+=cc; return; }
    int mid=l+r>>1,lc=x<<1,rc=lc|1;
    pushdown(x);
    upd(lc,l,mid); upd(rc,mid+1,r);
    pushup(x);
}
int query(const int x,const int l,const int r)
{
    if(rx<l||r<lx) return -1;
    if(lx<=l&&r<=rx) return seg[x].flag;
    pushdown(x);
    int mid=l+r>>1,lc=x<<1,rc=lc|1;
    return max(query(lc,l,mid),query(rc,mid+1,r));
}

struct node{int x,i,ev;};
inline bool operator <(const node x,const node y){return x.x<y.x;}
priority_queue<node>q;

bool judge(const node x)
{
    int oth=ci[x.i]-x.ev;
    int ii=xi[x.i]==0?u:(oth/xi[x.i]+(oth%xi[x.i]?1:0));
    lx=ii,rx=u; cc=1; upd(1,1,u);
    if(seg[1].mx>0) { cc=-1; upd(1,1,u); return false; }
    return true;
}

ll ans[maxn];

int main()
{
    scanf("%d%d%d",&n,&m,&K);
    for(int i=1;i<=n;i++) scanf("%d%d%d%d",&a[i],&s[i],&ci[i],&xi[i]);

    u=100000; build(1,1,u);
    for(int i=1;i<=n;i++) q.push((node){a[i]+s[i],i,0});

    ll now=0;
    for(int i=1;i<=u;i++)
    {
        int j=m;
        while(j&&!q.empty())
        {
            node x=q.top(); q.pop();
            if(judge(x))
            {
                j--; now+=x.x;
                x.ev++; x.x=a[x.i];
                if(x.ev!=ci[x.i]) q.push(x);
            }
        }
        ans[i]=now;
        if(q.empty())
        {
            for(int k=i+1;k<=u;k++) ans[k]=now;
            break;
        }
    }

    m=K;
    while(m--)
    {
        int x; scanf("%d",&x);
        printf("%lld\n",ans[x]);
    }

    return 0;
}

T3
听说把动态凸包的模板弄上去就能get AC
乐滋滋说不可做
uoj好像只有std过了qwq
那我还做这个干嘛

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值