Comet OJ - Contest #11题解

传送门

\(A\)

咕咕咕

const int N=1e6+5;
char s[N],t[N];int n,res;
inline bool cmp(const int &x,const int &y){return x>y;}
int main(){
    scanf("%s",s+1),n=strlen(s+1);
    fp(i,1,n)t[i]=s[i];sort(t+1,t+1+n,cmp);
    fp(i,1,n)res=(res*10+t[i]-s[i]),res=(res%10+10)%10;
    printf("%d\n",res);
    return 0;
}

\(B\)

先预处理出\(dp[i]\)表示花费\(i\)的代价最多能在\(n\)天之后获得的回报,然后直接\(dp\)就行了

//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
typedef long long ll;
const int N=10005;
ll dp[N],f[2][N],res;int w[N],n,m,k,t;
inline int calc(R int x){return x<=k?w[x]:0;}
int main(){
    scanf("%d%d%d",&n,&m,&k);
    fp(i,0,k)scanf("%d",&w[i]);
    memset(dp,0xef,sizeof(dp)),dp[0]=0;
    for(R int a,b;m;--m){
        scanf("%d%d",&a,&b);
        fp(i,a,2000)if(dp[i-a]>=0)cmax(dp[i],dp[i-a]+b);
    }
    memset(f[0],0xef,sizeof(f[0])),f[t=0][calc(0)]=0;
    fp(i,1,n-1){
        memset(f[t^1],0xef,sizeof(f[t^1]));
        fp(j,0,2000)if(f[t][j]>=0){
//          printf("%d %d %lld\n",i,j,f[t][j]);
            fp(l,0,j)
            cmax(f[t^1][j-l+calc(j-l)],f[t][j]+dp[l]);
        }
        t^=1;
    }
    res=-1e18;
    fp(i,0,2000)if(f[t][i]>=0)cmax(res,f[t][i]+i);
    printf("%lld\n",res);
    return 0;
}

\(C\)

我觉得应该只有我一个人是\(zz\)到写了个\(O(n\log n)\)的大常数做法结果居然跑过去了的人……

做法一

首先一段的长度显然不能超过\({(n-1)\over 2}\)。先破环成链,我们记\(las_i\)表示以\(i\)为结尾,最小的\(j\)满足\([j+1,i]\)是一个合法的区间,同理定义\(nxt_i\)表示最大的\(j\)满足\([i,j-1]\)是一个是一个合法的区间

我们枚举其中一个区间的末尾,那么最终得到的答案除以\(3\)就是原来的答案了

假设末尾为\(t\),那么这个环的开头就是\(s=t-n+1\),我们需要数的就是满足\(i\in[las_j,j-1],i\in [s,nxt_s-1],j\in [las_t,i-1]\)的数对\(i,j\)的个数

我们可以把每个\(j\)看做一个对于\([las_j,j-1]\)的区间加,用个指针保证只有\(j\in [las_t,i-1]\)的区间有贡献,然后区间查询\([s,nxt_s-1]\)就可以了。一开始用线段树似乎\(MLE\)了,后来改成树状数组结果卡了半天的常最后\(955ms\)过了此题……

做法二

不破环成链了,定义稍微改一改,记\(las_i\)表示以\(i-1\)为结尾的最小的\(j\)满足\([j,i]\)是一个合法的区间(只考虑\(j>i\)的那些,也就是说这个区间实际上是\([j,n]|[1,i-1]\)),以及\(nxt_i\)表示最大的\(j\)满足\([i,j]\)是个合法的区间

我们枚举\(a,b\),则需要满足的条件是\(b\in [a+1,nxt_a+1],c\in [b+1,nxt_b+1],c\in[las_a,n]\)

为了方便起见我们把所有\(nxt_b>n-1\)的都设为\(n-1\),可以看出不会影响答案

因为每一个区间的长度都小于等于\({(n-1)\over 2}\),所以\(b<las_a\)恒成立,那么\(c\)的合法的取值方案就是\(nxt_b+2-las_a\)

那么我们枚举\(a\),用双指针维护所有合法的\(b\)的贡献即可

具体细节可以参考代码

代码一

//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
typedef long long ll;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
    R int res,f=1;R char ch;
    while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
    for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
    return res*f;
}
const int N=4e6+5;
ll d[N];int c[N];
int a[N],las[N],nxt[N],pos[N],n,m,len;ll res;
inline int max(R int x,R int y){return x>y?x:y;}
inline int min(R int x,R int y){return x<y?x:y;}
inline void chgd(R int x,R int v){for(;x<=m;x+=x&-x)d[x]+=v;}
inline void chgc(R int x,R int v){for(;x<=m;x+=x&-x)c[x]+=v;}
inline void upd(R int l,R int r,R int v){
    chgc(r+1,-v),chgd(r+1,-v*(r+1));
    if(l!=0)chgc(l,v),chgd(l,v*l);
}
inline int askc(R int x){R int res=0;for(;x;x-=x&-x)res+=c[x];return res;}
inline ll askd(R int x){R ll res=0;for(;x;x-=x&-x)res+=d[x];return res;}
inline ll query(R int l,R int r){
    R ll res=0;
    res+=1ll*(r+1)*askc(r)-askd(r);
    if(l>1)res-=1ll*l*askc(l-1)-askd(l-1);
    return res;
}
int main(){
//  freopen("testdata.in","r",stdin);
    n=read(),m=n<<1;
    fp(i,1,n)a[i]=read(),a[n+i]=a[i];
    len=(n-1)>>1;
    las[0]=0,nxt[n<<1|1]=(n<<1|1);
    fp(i,1,n<<1)las[i]=max(las[i-1],max(i-len,pos[a[i]])),pos[a[i]]=i;
    fp(i,1,n)pos[i]=(n<<1|1);
    fd(i,n<<1,1)nxt[i]=min(nxt[i+1],min(i+len,pos[a[i]])),pos[a[i]]=i;
//  fp(i,2,n)upd(las[i],i-1,1);
    fp(i,las[n+1],n)upd(las[i],i-1,1);
    for(R int i=n+1,j=las[n+1];i<=(n<<1);++i){
        while(j<las[i])upd(las[j],j-1,-1),++j;
        res+=query(i-n+1,nxt[i-n+1]-1);
        upd(las[i],i-1,1);
    }
    printf("%lld\n",res/3);
    return 0;
}

代码二

//minamoto
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
typedef long long ll;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
    R int res,f=1;R char ch;
    while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
    for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
    return res*f;
}
const int N=4e6+5;
int a[N],las[N],nxt[N],pos[N],c[N],n,m,len,cnt;ll res,sum;
inline int max(R int x,R int y){return x>y?x:y;}
inline int min(R int x,R int y){return x<y?x:y;}
int main(){
//  freopen("testdata.in","r",stdin);
    n=read(),len=(n-1)>>1;
    fp(i,1,n)a[i]=read(),a[n+i]=a[i];
    las[0]=0,nxt[n<<1|1]=(n<<1|1);
    fp(i,1,n<<1)las[i]=max(las[i-1],max(i-len+1,pos[a[i]]+1)),pos[a[i]]=i;
    fp(i,1,n)pos[i]=(n<<1|1);
    fd(i,n<<1,1)nxt[i]=min(nxt[i+1],min(i+len-1,pos[a[i]]-1)),pos[a[i]]=i;
    fp(i,1,n)las[i]=las[i+n-1],cmin(nxt[i],n-1);
    /*
        fp(i,1,n)if(las[i]>i){
            fp(j,i+1,nxt[i]+1)if(nxt[j]+1>=las[i])res+=nxt[j]+2-las[i];
        }else break;
    */
    for(R int i=1,j=1,l=1,r=1;i<=n;++i){
        if(las[i]<=i)break;
        while(r<=nxt[i]+1)++cnt,++c[nxt[r]+1],sum+=nxt[r]+2,++r;
        while(l<r&&(l<=i||nxt[l]+1<las[i]))--cnt,--c[nxt[l]+1],sum-=nxt[l]+2,++l;
        res+=sum-1ll*cnt*las[i];
    }
    printf("%lld\n",res);
    return 0;
}

\(D\)

类似于\(kruskal\)重构树的过程,我们从小到大枚举点,且只考虑那些从大连向小的边。对于新建出的这棵树,我们要保证每个点都小于其父亲节点,所以对于当前点枚举所有出边,把对应的连通块接到当前点的子树里就行了

那么这就是一个类似于\(kruskal\)重构树的东西了,询问的时候倍增\(+\)线段树就行了

//quming
#include<bits/stdc++.h>
#define R register
#define pb emplace_back
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int P=998244353;
inline void upd(R int &x,R int y){(x+=y)>=P?x-=P:0;}
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
    R int res=1;
    for(;y;y>>=1,x=mul(x,x))(y&1)?res=mul(res,x):0;
    return res;
}
const int N=5e5+5;
vector<int>to[N];
struct eg{int v,nx;}e[N<<1];int head[N],tot;
inline void Add(R int u,R int v){e[++tot]={v,head[u]},head[u]=tot;}
int a[N],rk[N],dfn[N],low[N],fa[N][35],ga[N],dep[N],Log[N],tim,n,m,q;
inline int find(R int x){return ga[x]==x?x:ga[x]=find(ga[x]);}
struct node;typedef node* ptr;
struct node{
    ptr lc,rc;int v;
    inline void upd(){v=mul(lc->v,rc->v);}
}ee[N<<2],*pp=ee,*rt;
void build(ptr &p,int l,int r){
    p=++pp;if(l==r)return p->v=a[rk[r]],void();
    int mid=(l+r)>>1;
    build(p->lc,l,mid),build(p->rc,mid+1,r);
    p->upd();
}
void update(ptr p,int l,int r,int x,int v){
    if(l==r)return p->v=v,void();
    int mid=(l+r)>>1;
    x<=mid?update(p->lc,l,mid,x,v):update(p->rc,mid+1,r,x,v);
    p->upd();
}
int query(ptr p,int l,int r,int ql,int qr){
    if(ql<=l&&qr>=r)return p->v;
    int mid=(l+r)>>1,res=1;
    if(ql<=mid)res=mul(res,query(p->lc,l,mid,ql,qr));
    if(qr>mid)res=mul(res,query(p->rc,mid+1,r,ql,qr));
    return res;
}
void dfs(int u,int f){
    dfn[u]=++tim,rk[tim]=u,fa[u][0]=f;
    fp(i,1,20)fa[u][i]=fa[fa[u][i-1]][i-1];
    go(u)dfs(v,u);
    low[u]=tim;
}
inline int jump(R int u,R int x){
    if(u>x)return 0;
//  R int k=dep[u];
    fd(i,20,0)if(fa[u][i]&&fa[u][i]<=x)u=fa[u][i];
    return query(rt,1,n,dfn[u],low[u]);
}
int main(){
//  freopen("testdata.in","r",stdin);
    scanf("%d%d%d",&n,&m,&q);
    fp(i,1,n)scanf("%d",&a[i]),ga[i]=i,a[i]%=P;
    for(R int i=1,u,v;i<=m;++i)scanf("%d%d",&u,&v),to[u].pb(v),to[v].pb(u);
    fp(u,1,n)for(auto v:to[u])if(v<u&&u!=find(v))Add(u,find(v)),ga[find(v)]=u;
//  fp(i,1,n)fa[i][0]=ga[i];
    Log[0]=-1;fp(i,2,n)Log[i]=Log[i>>1]+1;
    dfs(n,0);
    build(rt,1,n);
    for(int op,u,v;q;--q){
        scanf("%d%d%d",&op,&u,&v);
        if(op==1)printf("%d\n",jump(u,v));
            else update(rt,1,n,dfn[u],v%P);
    }
    return 0;
}

剩下两题明天再补吧

猜你喜欢

转载自www.cnblogs.com/yuanquming/p/11575280.html