【SDOI2016Round1】【解题报告】

Day1

T1:

题意:求∑n?1i=0∑m?1j=0max((i xor j)?k,0)

因为是抑或操作,每一位都是独立的,所以可以一位一位的算贡献。

f[i][a][b][c]表示第i位时,每个数跟n,m,k的大小关系,0表示小于,1表示i位之前都相等,2表示大于。转移的时候美剧当前这一位的数是什么,从高位向低位转移就行了。

复杂度是O(nlogn)

code:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define LL long long
const int N=100;
int T,Mod,ni[N],mi[N],ki[N],len;
LL n,m,K,f[N][2][2][3],g[N][2][2][3];
inline void calc(){
    int i,a,b,c,o0,o1,x,y,z,o;
    g[0][1][1][1]=1;
    for(i=0;i<len;++i)
      for(a=0;a<=1;++a)
        for(b=0;b<=1;++b)
          for(c=0;c<=2;++c)
            if(f[i][a][b][c]+g[i][a][b][c])
              for(o0=0;o0<=1;++o0){
                if(a){
                    if(o0>ni[i+1]) continue;
                    if(o0==ni[i+1]) x=1;
                    if(o0<ni[i+1]) x=0;
                }
                else x=0;
                for(o1=0;o1<=1;++o1){
                    if(b){
                        if(o1>mi[i+1]) continue;
                        if(o1==mi[i+1]) y=1;
                        if(o1<mi[i+1]) y=0;
                    }
                    else y=0;
                    o=o0^o1;
                    if(c==0||c==2) z=c;
                    if(c==1){
                        if(o>ki[i+1]) z=2;
                        if(o==ki[i+1]) z=1;
                        if(o<ki[i+1]) z=0;
                    }
                    g[i+1][x][y][z]=(g[i+1][x][y][z]+g[i][a][b][c])%Mod;
                    f[i+1][x][y][z]=(f[i+1][x][y][z]+f[i][a][b][c]*2LL+g[i][a][b][c]*(LL)o)%Mod;
                }
              }
}
int main(){
    scanf("%d",&T);
    while(T--){
        LL x;
        int i;
        memset(f,0,sizeof(f));
        memset(g,0,sizeof(g));
        memset(ni,0,sizeof(ni));
        memset(mi,0,sizeof(mi));
        memset(ki,0,sizeof(ki));
        scanf("%lld%lld%lld%d",&n,&m,&K,&Mod);
        for(x=n;x;x>>=1) ni[++ni[0]]=x&1LL;
        for(x=m;x;x>>=1) mi[++mi[0]]=x&1LL;
        for(x=K;x;x>>=1) ki[++ki[0]]=x&1LL;
        len=max(ni[0],max(mi[0],ki[0]));
        for(i=1;i<=(len>>1);++i){
            swap(ni[i],ni[len-i+1]);
            swap(mi[i],mi[len-i+1]);
            swap(ki[i],ki[len-i+1]);
        }
        calc();
        printf("%lld\n",(f[len][0][0][2]-(K%Mod*g[len][0][0][2])%Mod+Mod)%Mod);
    }
}

T2:

题意:给出n种数字,第i个是ai,个数是bi,权值是ci。如果ai|aj而且aiaj是一个质数,那么这两个数字就能获得ci?cj的价值,要求总价值不小于0的情况下求最多的配对数。

配对关系是一个二分图,所以建出费用流的图来,当跑到费用小于0的时候,处理一下当前的流量,退出就行了。

code:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define T n+2
#define D 795
#define LL long long
#define inf 1000000000
#define INF 10000000000000LL
const int N=800;
const int M=100000;
const int O=2000000;
bool flag[M+10],use[N],f[N];
struct S{int st,en,va;LL co;}aa[O];
int n,a[N],b[N],c[N],prime[M+10],d[N],va,point[N],pre[N],next[O],map[N][N],tot=1,co[N];
int l[N],to[N];
LL dis[N];
inline void prepare(){
    int i,j;
    for(i=2;i<=M;++i){
        if(!flag[i]) prime[++prime[0]]=i;
        for(j=1;j<=prime[0]&&i*prime[j]<=M;++j){
            flag[i*prime[j]]=true;
            if(i%prime[j]==0) break;
        }
    }
}
inline void add(int x,int y,int z,LL co){
    next[++tot]=point[x];point[x]=tot;
    aa[tot].st=x;aa[tot].en=y;aa[tot].va=z;aa[tot].co=co;
    next[++tot]=point[y];point[y]=tot;
    aa[tot].st=y;aa[tot].en=x;aa[tot].va=0;aa[tot].co=-co;
}
inline bool check(int x,int y){
    int i,j,now,num=0;
    if((a[x]%a[y])||(a[x]==a[y])) return false;
    now=a[x]/a[y];
    for(i=1;i<=prime[0];++i){
        while(now%prime[i]==0) ++num,now/=prime[i];
        if(num>1) return false;
        if(now==1) return true;
    }
    if(now!=1) ++num;
    return num==1;
}
inline void paint(int x,int kind){
    int i;
    co[x]=kind;
    for(i=1;i<=n;++i)
      if(map[x][i]&&!co[i])
        paint(i,kind==1?2:1);
}
inline LL SPFA(int x,int y){
    int h=0,t=1,i,u;
    l[t]=x;
    for(i=1;i<=T;++i) dis[i]=-INF;
    dis[x]=0;
    while(h!=t){
        h=h%D+1;u=l[h];f[u]=true;
        for(i=point[u];i;i=next[i])
          if(aa[i].va>0&&dis[aa[i].en]<dis[u]+aa[i].co){
            dis[aa[i].en]=dis[u]+aa[i].co;
            pre[aa[i].en]=i;
            if(f[aa[i].en]){
                f[aa[i].en]=false;
                t=t%D+1;
                l[t]=aa[i].en;
            }
          }
    }
    return dis[y];
}
inline int ISAP(int x,int y){
    int minn=inf,i;
    for(i=y;i!=x;i=aa[pre[i]].st)
      minn=min(minn,aa[pre[i]].va);
    for(i=y;i!=x;i=aa[pre[i]].st){
        aa[pre[i]].va-=minn;
        aa[pre[i]^1].va+=minn;
    }
    return minn;
}
int main(){
    int i,j,o=0,num=0,maxn=0;
    prepare();
    scanf("%d",&n);
    for(i=1;i<=n;++i) scanf("%d",&a[i]);
    for(i=1;i<=n;++i) scanf("%d",&b[i]);
    for(i=1;i<=n;++i) scanf("%d",&c[i]),o+=(c[i]==0);
    for(i=1;i<=n;++i)
      for(j=1;j<=n;++j)
        if(check(i,j)) map[i][j]=map[j][i]=1;
    for(i=1;i<=n;++i)
      if(!co[i]) paint(i,1);
    for(i=1;i<=n;++i)
      if(co[i]==1) add(1,i+1,b[i],0);
      else add(i+1,T,b[i],0);
    for(i=1;i<=n;++i)
      for(j=i+1;j<=n;++j)
        if(map[i][j]||map[j][i]){
            int x=i,y=j;
            if(co[x]==2) swap(x,y);
            add(x+1,y+1,inf,(LL)c[x]*c[y]);
        }
    memset(f,1,sizeof(f));
    LL minn,ans=0;
    while(minn!=-INF){
        minn=SPFA(1,T);
        if(minn!=-INF){
            int now=ISAP(1,T);
            ans=ans+minn*(LL)now;
            if(ans<0LL){
                ans-=minn*(LL)now;
                printf("%d\n",num+min(now,(int)(-ans/minn)));
                return 0;
            }
            num+=now;
        }
    }
    printf("%d\n",num);
}

T3:

题意:给出一棵树,有点权和边权,有两种操作,一种是将一条路径上的点权修改成min(v[x],a?dis[x]+b),dis[x] 表示x到起点的距离(只算边权)。另一种是询问a到b路径中最小的点权。

第一种修改可以看成是往树上的一段区间中加入一个线段。这个东西可以用线段树维护。用线段树维护这个区间的线段的斜率和截距。每次向这个区间中加入一条新的线段的时候,看一下这段区间中原来的线段和新加入的线段哪一个对这段区间的影响更大,将影响小的线段下放到它有影响的子树,每次一直这样下放到叶子节点。这样每次插入的复杂度是O(log2n)。

每次查询的时候只需要看一下这段区间中的最小值和这段区间中所保存的线段的两个端点的情况就行了,复杂度是O(logn)。

这道题每次的dis数组还是不知道的,可以在加入线段的时候顺便将lca传进去(常数大了好多。。。)

再加上链剖,总的复杂度就是O(nlog3n)

code:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define mid (l+r)/2
#define L k<<1,l,mid
#define R k<<1|1,mid+1,r
#define LL long long
#define D 123456789123456789LL
const int N=100010;
LL dis[N],a,b;
struct S{int st,en,va;}aa[N<<1];
struct T{int lca,st,kind;LL k,b,minn;}tr[N<<2];
int n,m,point[N],next[N<<1],tot,deep[N],siz[N],son[N],belong[N],fa[N][21],q[N],pos[N],dfsn,cur[N],lca,to[N],flag[N<<2];
inline int in(){
    int f=1,x=0;char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){
        if(ch==‘-‘) f=-1;
        ch=getchar();
    }
    while(ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-‘0‘,ch=getchar();
    return x*f;
}
inline int IN(){
    LL f=1,x=0;char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){
        if(ch==‘-‘) f=-1;
        ch=getchar();
    }
    while(ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-‘0‘,ch=getchar();
    return x*f;
}
inline void add(int x,int y,int z){
    next[++tot]=point[x];point[x]=tot;
    aa[tot].st=x;aa[tot].en=y;aa[tot].va=z;
    next[++tot]=point[y];point[y]=tot;
    aa[tot].st=y;aa[tot].en=x;aa[tot].va=z;
}
inline void prepare(){
    int h=1,t=1,u,i,j;
    q[h]=1;
    while(h<=t){
        u=q[h];
        for(i=point[u];i;i=next[i])
          if(aa[i].en!=fa[u][0]){
            q[++t]=aa[i].en;
            deep[aa[i].en]=deep[u]+1;
            fa[aa[i].en][0]=u;
            dis[aa[i].en]=dis[u]+(LL)aa[i].va;
            for(j=1;j<=20;++j)
              fa[aa[i].en][j]=fa[fa[aa[i].en][j-1]][j-1];
          }
        h+=1;
    }
    for(i=t;i;--i){
        u=q[i];siz[u]=1;
        for(j=point[u];j;j=next[j])
          if(aa[j].en!=fa[u][0]){
            siz[u]+=siz[aa[j].en];
            if(siz[aa[j].en]>siz[son[u]]) son[u]=aa[j].en;
          }
    }
    int now=1;
    for(i=1;i<=n;++i) cur[i]=point[i];
    while(now){
        if(!pos[now]){
            pos[now]=++dfsn;
            to[dfsn]=now;
            belong[now]=(now==son[fa[now][0]] ? belong[fa[now][0]] : now);
            now=(son[now] ? son[now] : fa[now][0]);
        }
        else{
            for(i=cur[now];i&&(aa[i].en==fa[now][0]||aa[i].en==son[now]);i=next[i]);
            cur[now]=next[i];
            belong[aa[i].en]=aa[i].en;
            now=(i ? aa[i].en : fa[now][0]);
        }
    }
}
inline int LCA(int x,int y){
    if(deep[x]<deep[y]) swap(x,y);
    int t=deep[x]-deep[y],i;
    for(i=0;i<=20;++i)
      if(t&(1<<i)) x=fa[x][i];
    for(i=20;~i;--i)
      if(fa[x][i]!=fa[y][i])
        x=fa[x][i],y=fa[y][i];
    return x==y?x:fa[x][0];
}
inline void build(int k,int l,int r){
    if(l==r){
        tr[k].k=0;
        tr[k].kind=-1;
        tr[k].lca=to[l];
        tr[k].b=tr[k].minn=D;
        return ;
    }
    build(L);build(R);
    tr[k]=tr[k<<1];
}
inline int LL calc(int x,int y,int z,int kind){
    x=to[x];
    if(kind==0) return dis[z]-dis[x];
    if(kind==1) return dis[z]-dis[y]+dis[x]-dis[y];
}
inline void insert(int k,int l,int r,int x,int y,T now){
    if(x<=l&&y>=r){
        LL minn=D;
        minn=min(minn,calc(l,now.lca,now.st,now.kind)*now.k+now.b);
        minn=min(minn,calc(r,now.lca,now.st,now.kind)*now.k+now.b);
        now.minn=tr[k].minn=min(tr[k].minn,minn);
        if(!flag[k]){
            flag[k]=1;
            tr[k]=now;
            return ;
        }
        int o1=calc(l,now.lca,now.st,now.kind)*now.k+now.b<calc(l,tr[k].lca,tr[k].st,tr[k].kind)*tr[k].k+tr[k].b;
        if(l==r){
            if(o1) tr[k]=now;
            return ;
        }
        int o2=calc(mid,now.lca,now.st,now.kind)*now.k+now.b<calc(mid,tr[k].lca,tr[k].st,tr[k].kind)*tr[k].k+tr[k].b;
        int o3=calc(r,now.lca,now.st,now.kind)*now.k+now.b<calc(r,tr[k].lca,tr[k].st,tr[k].kind)*tr[k].k+tr[k].b;
        if(o1&&o3){
            tr[k]=now;
            return ;
        }
        if(!o1&&!o3) return;
        if(o2){
            swap(tr[k],now);
            o1^=1;o3^=1;
        }
        if(o1) insert(L,x,y,now);
        if(o3) insert(R,x,y,now);
        return ;
    }
    if(x<=mid) insert(L,x,y,now);
    if(y>mid) insert(R,x,y,now);
    tr[k].minn=min(tr[k].minn,min(tr[k<<1].minn,tr[k<<1|1].minn));
}
inline LL query(int k,int l,int r,int x,int y){
    LL minn=D;
    if(x<=l&y>=r){
        LL o_l=calc(l,tr[k].lca,tr[k].st,tr[k].kind);
        LL o_r=calc(r,tr[k].lca,tr[k].st,tr[k].kind);
        return min(tr[k].minn,min(o_l*tr[k].k+tr[k].b,o_r*tr[k].k+tr[k].b));
    }
    minn=min(minn,calc(max(x,l),tr[k].lca,tr[k].st,tr[k].kind)*tr[k].k+tr[k].b);
    minn=min(minn,calc(min(y,r),tr[k].lca,tr[k].st,tr[k].kind)*tr[k].k+tr[k].b);
    if(x<=mid) minn=min(minn,query(L,x,y));
    if(y>mid) minn=min(minn,query(R,x,y));
    return minn;
}
inline void change(int x,int y,int st,int kind){
    int i,j;
    T now=(T){lca,st,kind,a,b,D};
    while(belong[x]!=belong[y]){
        insert(1,1,n,pos[belong[x]],pos[x],now);
        x=fa[belong[x]][0];
    }
    insert(1,1,n,pos[y],pos[x],now);
}
inline LL ask(int x,int y){
    LL minn=D;
    while(belong[x]!=belong[y]){
        minn=min(minn,query(1,1,n,pos[belong[x]],pos[x]));
        x=fa[belong[x]][0];
    }
    minn=min(minn,query(1,1,n,pos[y],pos[x]));
    return minn;
}
int main(){
    int i,j,x,y,t,z;
    n=in();m=in();
    for(i=1;i<n;++i){
        x=in();y=in();z=in();
        add(x,y,z);
    }
    prepare();
    build(1,1,n);
    while(m--){
        t=in();x=in();y=in();
        lca=LCA(x,y);
        if(t==1){
            a=IN();b=IN();
            change(x,lca,x,0);
            change(y,lca,x,1);
        }
        if(t==2) printf("%lld\n",min(ask(x,lca),ask(y,lca)));
    }
}

Day2:

T1:

题意:每次向一个字符串的结尾加一个字符,输出当前有多少种不同的非空子串。

先将这个字符串全读进来,然后把字符串反过来建后缀数组。总的答案就是n?(n+1)2?∑n?1i=1height[i]

因为要动态的查询,所以维护一个rank的权值线段树,每次加入一个之后查询一下前驱和后继,每次更新的答案就是:n?i?lcp(now,pre)?lcp(now,sub)+lcp(pre,sub)

code:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define LL long long
#define inf 0x7fffffff
const int N=100010;
struct S{int minn,maxn;}tr[N<<2];
int n,a[N],b[N],m,t1[N],t2[N],sa[N],rank[N],c[N],height[N],st[N][21],Log[N];
inline int in(){
    int x=0;char ch=getchar();
    while(ch<‘0‘||ch>‘9‘) ch=getchar();
    while(ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-‘0‘,ch=getchar();
    return x;
}
inline bool cmp(int *y,int p,int q,int k){
    int o0,o1;
    o0=(p+k>=n)?-1:y[p+k];
    o1=(q+k>=n)?-1:y[q+k];
    return o0==o1&&y[p]==y[q];
}
inline void build_sa(){
    int i,k,p,*x=t1,*y=t2;
    for(i=0;i<m;++i) c[i]=0;
    for(i=0;i<n;++i) ++c[x[i]=a[i]];
    for(i=1;i<m;++i) c[i]+=c[i-1];
    for(i=n-1;~i;--i) sa[--c[x[i]]]=i;
    for(k=1;k<=n;k<<=1){
        for(p=0,i=n-k;i<n;++i) y[p++]=i;
        for(i=0;i<n;++i) if(sa[i]>=k) y[p++]=sa[i]-k;
        for(i=0;i<m;++i) c[i]=0;
        for(i=0;i<n;++i) ++c[x[y[i]]];
        for(i=1;i<m;++i) c[i]+=c[i-1];
        for(i=n-1;~i;--i) sa[--c[x[y[i]]]]=y[i];
        swap(x,y);
        x[sa[0]]=0;m=1;
        for(i=1;i<n;++i) x[sa[i]]=(cmp(y,sa[i],sa[i-1],k)?m-1:m++);
        if(m>=n) break;
    }
}
inline void build_height(){
    int i,j,k=0;
    for(i=0;i<n;++i) rank[sa[i]]=i;
    for(i=0;i<n;++i){
        k=k?--k:k;
        j=sa[rank[i]-1];
        while(a[i+k]==a[j+k]) ++k;
        height[rank[i]]=k;
    }
    /*------------st------------*/
    memset(st,127/3,sizeof(st));
    for(i=0;i<n;++i) st[i][0]=height[i];
    for(j=1;j<=20;++j)
      for(i=0;i+(1<<(j-1))<n;++i)
        st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
    for(j=0,i=1;i<=n;++i){
        if((1<<(j+1))<=i) ++j;
        Log[i]=j;
    }
}
inline int LCP(int x,int y){
    int k=Log[y-x];++x;
    return min(st[x][k],st[y-(1<<k)+1][k]);
}
#define mid (l+r)/2
#define L k<<1,l,mid
#define R k<<1|1,mid+1,r
inline S update(S x,S y){
    S ans;
    ans.maxn=max(x.maxn,y.maxn);
    ans.minn=min(x.minn,y.minn);
    return ans;
}
inline void build_tree(int k,int l,int r){
    if(l==r){
        tr[k].minn=inf;
        tr[k].maxn=-inf;
        return ;
    }
    build_tree(L);build_tree(R);
    tr[k]=update(tr[k<<1],tr[k<<1|1]);
}
inline void insert(int k,int l,int r,int x){
    if(l==r){
        tr[k].maxn=tr[k].minn=l;
        return ;
    }
    if(x<=mid) insert(L,x);
    else insert(R,x);
    tr[k]=update(tr[k<<1],tr[k<<1|1]);
}
inline S query(int k,int l,int r,int x,int y){
    S ans1,ans2;
    bool f1=false,f2=false;
    if(x<=l&&y>=r) return tr[k];
    if(x<=mid) ans1=query(L,x,y),f1=true;
    if(y>mid) ans2=query(R,x,y),f2=true;
    if(f1&&f2) return update(ans1,ans2);
    else return f1?ans1:ans2;
}
int main(){
    int i;
    n=in();
    for(i=n-1;~i;--i) a[i]=b[i]=in();
    sort(b+1,b+n+1);
    m=unique(b+1,b+n+1)-b-1;
    for(i=0;i<n;++i) a[i]=lower_bound(b+1,b+m+1,a[i])-b-1;
    build_sa();
    build_height();
    build_tree(1,0,n-1);
    for(LL ans=0,i=n-1;~i;--i){
        ans+=(LL)(n-i);
        int now=rank[i];
        int pre=now?query(1,0,n-1,0,now-1).maxn:-inf;
        int sub=(now==n-1)?inf:query(1,0,n-1,now+1,n-1).minn;
        if(pre!=-inf) ans-=(LL)LCP(pre,now);
        if(sub!=inf) ans-=(LL)LCP(now,sub);
        if(pre!=-inf&&sub!=inf) ans+=(LL)LCP(pre,sub);
        insert(1,0,n-1,now);
        printf("%lld\n",ans);
    }
}

T2:

题意:求有多少长度为n的序列,满足1~n只出现过一次,而且恰好有m个数满足a[i]=i。

答案就是C(n,m)?f[n?m]

C(n,m)表示m个满足条件的数怎样选的方案数,再乘上剩下的所有n?m个数都不在多对应的位置上的方案数,也就是错排。

错拍的公式就是:f[i]=(i?1)?(f[i?1]+f[i?2])

求c的时候预处理一下阶乘。

code:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define LL long long
#define Mod 1000000007LL
const int M=1000000;
LL f[M+10],g[M+10];
int T,n,m;
inline int in(){
    int x=0;char ch=getchar();
    while(ch<‘0‘||ch>‘9‘) ch=getchar();
    while(ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-‘0‘,ch=getchar();
    return x;
}
inline LL quickpow(LL x,LL y){
    LL ans=1;
    while(y){
        if(y&1LL) ans=(ans*x)%Mod;
        y>>=1LL; x=(x*x)%Mod;
    }
    return ans;
}
int main(){
    int i;
    T=in();
    for(f[1]=0LL,f[2]=1LL,f[0]=1LL,i=3;i<=M;++i) f[i]=(LL)(i-1)*((f[i-1]+f[i-2])%Mod)%Mod;
    for(g[1]=g[0]=1LL,i=2;i<=M;++i) g[i]=(g[i-1]*(LL)i)%Mod;
    while(T--){
        n=in();m=in();
        if(m>n){
            printf("0\n");
            continue;
        }
        LL ans=f[n-m]*((g[n]*quickpow(g[m],Mod-2)%Mod)*quickpow(g[n-m],Mod-2)%Mod)%Mod;
        printf("%lld\n",ans);
    }
}

T3:

题意:有一个长度为n的序列,每个节点都有一个权值,分成m份,求m份的最小的方差是多少。答案要求?m2。

ans=m?∑mi=1(xi?xˉ)2

=m?∑mi?1(xi2+xˉ2?2xi?xˉ)

把∑拆开之后,后面两项都是常数,就相当于求每段的平方和的最大。这个东西可以斜率优化。

code:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define LL long long
const int N=3010;
LL f[N][N],a[N];
int n,m,h[N],t[N],q[N][N];
inline LL pow(LL x){return x*x;}
inline LL get_son(int x,int y,int z){
    return f[z][x]+pow(a[x])-f[z][y]-pow(a[y]);
}
inline LL get_fa(int x,int y){
    return a[x]-a[y];
}
inline LL calc(int x,int y,int z){
    return f[z][x]+pow(a[y]-a[x]);
}
int main(){
    int i,j;
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;++i)
      scanf("%lld",&a[i]),a[i]+=a[i-1];
    memset(f,127/3,sizeof(f));
    for(j=0;j<=m;++j) f[j][0]=0,q[j][h[j]=t[j]=1]=0;
    for(j=1;j<=m;++j)
      for(i=1;i<=n;++i){
        while(h[j-1]<t[j-1]&&get_son(q[j-1][h[j-1]+1],q[j-1][h[j-1]],j-1)<get_fa(q[j-1][h[j-1]+1],q[j-1][h[j-1]])*(LL)a[i]*2LL) ++h[j-1];
        f[j][i]=calc(q[j-1][h[j-1]],i,j-1);
        while(h[j]<t[j]&&get_son(i,q[j][t[j]],j)*get_fa(q[j][t[j]],q[j][t[j]-1])<get_son(q[j][t[j]],q[j][t[j]-1],j)*get_fa(i,q[j][t[j]])) --t[j];
        q[j][++t[j]]=i;
      }
    printf("%lld\n",f[m][n]*(LL)m-pow(a[n]));
}
时间: 2024-11-24 10:00:42

【SDOI2016Round1】【解题报告】的相关文章

[SDOI2016Round1]解题报告

Day1 T1: 题意:求∑n?1i=0∑m?1j=0max((i xor j)?k,0) 由于是抑或操作.每一位都是独立的,所以能够一位一位的算贡献. f[i][a][b][c]表示第i位时.每一个数跟n,m,k的大小关系.0表示小于,1表示i位之前都相等,2表示大于.转移的时候美剧当前这一位的数是什么.从高位向低位转移即可了. 复杂度是O(nlogn) code: #include<iostream> #include<cstdio> #include<cstring&g

解题报告 之 POJ3057 Evacuation

解题报告 之 POJ3057 Evacuation Description Fires can be disastrous, especially when a fire breaks out in a room that is completely filled with people. Rooms usually have a couple of exits and emergency exits, but with everyone rushing out at the same time

hdu 1541 Stars 解题报告

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1541 题目意思:有 N 颗星星,每颗星星都有各自的等级.给出每颗星星的坐标(x, y),它的等级由所有比它低层(或者同层)的或者在它左手边的星星数决定.计算出每个等级(0 ~ n-1)的星星各有多少颗. 我只能说,题目换了一下就不会变通了,泪~~~~ 星星的分布是不是很像树状数组呢~~~没错,就是树状数组题来滴! 按照题目输入,当前星星与后面的星星没有关系.所以只要把 x 之前的横坐标加起来就可以了

【百度之星2014~初赛(第二轮)解题报告】Chess

声明 笔者最近意外的发现 笔者的个人网站http://tiankonguse.com/ 的很多文章被其它网站转载,但是转载时未声明文章来源或参考自 http://tiankonguse.com/ 网站,因此,笔者添加此条声明. 郑重声明:这篇记录<[百度之星2014~初赛(第二轮)解题报告]Chess>转载自 http://tiankonguse.com/ 的这条记录:http://tiankonguse.com/record/record.php?id=667 前言 最近要毕业了,有半年没做

2016 第七届蓝桥杯 c/c++ B组省赛真题及解题报告

2016 第七届蓝桥杯 c/c++ B组省赛真题及解题报告 勘误1:第6题第4个 if最后一个条件粗心写错了,答案应为1580. 条件应为abs(a[3]-a[7])!=1,宝宝心理苦啊.!感谢zzh童鞋的提醒. 勘误2:第7题在推断连通的时候条件写错了,后两个if条件中是应该是<=12 落了一个等于号.正确答案应为116. 1.煤球数目 有一堆煤球.堆成三角棱锥形.详细: 第一层放1个, 第二层3个(排列成三角形), 第三层6个(排列成三角形), 第四层10个(排列成三角形). -. 假设一共

[noip2011]铺地毯(carpet)解题报告

最近在写noip2011的题,备战noip,先给自己加个油! 下面是noip2011的试题和自己的解题报告,希望对大家有帮助,题目1如下 1.铺地毯(carpet.cpp/c/pas) [问题描述]为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯.一共有n 张地毯,编号从1 到n.现在将这些地毯按照编号从小到大的顺序平行于坐标轴先后铺设,后铺的地毯覆盖在前面已经铺好的地毯之上.地毯铺设完成后,组织者想知道覆盖地面某个点的最上面的那张地毯的

ACdream 1203 - KIDx&#39;s Triangle(解题报告)

KIDx's Triangle Time Limit: 2000/1000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others) Submit Statistic Next Problem Problem Description One day, KIDx solved a math problem for middle students in seconds! And than he created this problem. N

解题报告 之 CodeForces 91B Queue

解题报告 之 CodeForces 91B Queue Description There are n walruses standing in a queue in an airport. They are numbered starting from the queue's tail: the 1-st walrus stands at the end of the queue and the n-th walrus stands at the beginning of the queue.

解题报告 之 POJ1226 Substrings

解题报告 之 POJ1226 Substrings Description You are given a number of case-sensitive strings of alphabetic characters, find the largest string X, such that either X, or its inverse can be found as a substring of any of the given strings. Input The first li

解题报告 之 UVA563 Crimewave

解题报告 之 UVA563 Crimewave Description Nieuw Knollendam is a very modern town. This becomes clear already when looking at the layout of its map, which is just a rectangular grid of streets and avenues. Being an important trade centre, Nieuw Knollendam a