【Codeforces】Manthan, Codefest 18 (Div. 1 + Div. 2) E,F,G

版权声明:转载请附带链接或评论 https://blog.csdn.net/corsica6/article/details/82387428

传送门:CodeforcesRound1037
这场的题解,标程都不太友好啊。。。



E. Trips

题解

考虑倒着回答询问,假设所有人都将去旅行,再考虑不满足条件的逐一删去。
d i 表示结点 i 在旅行网中的度数(已经删去的点不再考虑),用 s e t p a i r ( d i , i ) ,按 d i 升序排列。
不断弹出旅行网中度数 < k 的点,再逐一更新与之相连的点的度数即可,每次操作断掉一条边,记录 s e t 中剩余的点数即为答案。

代码

#include<bits/stdc++.h>
#define pii pair<int,int>
#define mkp make_pair
#define fi first
#define sc second
using namespace std;
const int N=2e5+10;
int n,m,k,d[N],ans[N],in[N],sum;
pii rl[N],tp;
vector<pii>g[N];
set<pii>S;

int main(){
    int i,j,q,x,y;
    scanf("%d%d%d",&n,&m,&k);
    sum=n;
    for(i=1;i<=m;++i){
        scanf("%d%d",&x,&y);
        rl[i].fi=x;rl[i].sc=y;
        d[x]++;d[y]++;
        g[x].push_back(mkp(y,i));
        g[y].push_back(mkp(x,i));
    }
    for(i=1;i<=n;++i)
        in[i]=1,S.insert(mkp(d[i],i));
    for(i=m;i;--i){
       if(!sum) {ans[i]=0;continue;}
       set<pii>::iterator iter=S.begin();
       for(tp=*iter;(!S.empty()) && ((!in[tp.sc])||(d[tp.sc]!=tp.fi)||(tp.fi<k));){
          if(!in[tp.sc] || (d[tp.sc]!=tp.fi)) S.erase(iter);
          else{
             S.erase(iter);
             in[tp.sc]=0;sum--;
             for(q=g[tp.sc].size()-1;~q;--q){
                j=g[tp.sc][q].fi;if(!in[j] || g[tp.sc][q].sc>i) continue;
                d[j]--;S.insert(mkp(d[j],j));
             }
          }
          if(S.empty()) break;
          else iter=S.begin(),tp=*iter;
       }
       ans[i]=sum;x=rl[i].fi;y=rl[i].sc;
       if(in[x] && in[y]) 
       {d[x]--;d[y]--;S.insert(mkp(d[x],x));S.insert(mkp(d[y],y));}
    }
    for(i=1;i<=m;++i) printf("%d\n",ans[i]);
}

F. Maximum Reduction

题解

一个递归的过程显然可以转化为统计每个值的出现次数。
考虑单调栈处理出 L i , R i ,区间 [ L i , R i ] 表示 a i 为满足 a i = m a x j = L i R i a j 的最大区间。
对于第 i 个数 a i ,出现次数等价于长度为 k , 2 k 1 , 3 k 2 , . . . , n k n + 1 的左右端点在 [ L i , R i ] 范围内,且覆盖点 i 的区间个数。
c a l ( l , r ) 为长度如上的左右端点出现在 [ l , r ] 范围内的区间个数,显然是一个等差数列可以算出(这里预处理了一下),则 a i 的出现次数可以通过容斥得到: c a l ( l , r ) c a l ( l , i 1 ) c a l ( i + 1 , r )
复杂度 O ( n )

代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10,mod=1e9+7;
int n,k,a[N],q[N],top;
int L[N],R[N],v[N],s[N],tot;
int ans;

inline int ad(int x,int y){x+=y;return x>=mod?x-mod:x;}
inline int dc(int x,int y){x-=y;return x<0?x+mod:x;}
inline int mul(int x,int y){return 1ll*x*y%mod;}

inline int cal(int l,int r)
{
    if(l+k-1>r) return 0;
    int len=r-l+1,bs=len/(k-1);
    if(v[bs]>len) bs--;
    return ad(dc(mul(len,bs),s[bs]),bs);
}

int main(){
    int i,j;
    scanf("%d%d",&n,&k);
    for(i=1;i<=n;++i) scanf("%d",&a[i]),L[i]=1,R[i]=n;
    for(i=1;i<=n;++i){
        for(;top && a[q[top]]<a[i];top--) R[q[top]]=i-1;
        L[i]=q[top]+1;q[++top]=i;
    }
    for(i=1;;++i) {v[i]=i*k-i+1;if(v[i]>n) break;}
    tot=i-1;
    for(i=1;i<=tot;++i) s[i]=ad(s[i-1],v[i]);
    for(i=1;i<=n;++i) 
        ans=ad(ans,mul(a[i],dc(cal(L[i],R[i]),ad(cal(L[i],i-1),cal(i+1,R[i])))));
    printf("%d\n",ans);
}

G. A Game on Strings

题解

博弈论相关。处理出每个相同字符之间的区间的 s g 函数和其前缀后缀的 s g 函数。把所有需要处理的区间按长度排序,记忆化搜索预处理。每次询问整块和前后缀的 s g 函数异或得到答案。
复杂度 O ( 26 2 n + 26 Q ) (似乎忽略了记忆化搜索的复杂度?)

代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+100;

int n,m,id[N],num[26];
int ql[26][N],qr[26][N],fl[26][N],fr[26][N];
int w[26][N],pos[N],cnt,tot;
char s[N];

struct L{
  int len,l,r;
  L(){}
  L(int LEN,int QL,int QR){len=LEN;l=QL;r=QR;}
}le[N*30];

inline bool cmp(const L&x,const L&y){
   if(x.len!=y.len) return x.len<y.len;
   if(x.l!=y.l) return x.l<y.l;
   return x.r<y.r;
} 

inline int get(int l,int r)
{
    int i,j,st,ed,res=0,nw;
    for(i=0;i<26;++i)
     if(qr[i][l]<=r){
        nw=0;
        st=qr[i][l];ed=ql[i][r];
        for(j=id[st]+1;j<=id[ed];++j) nw^=w[i][j];
        if(l<st){
            if(fl[i][l]==-1) fl[i][l]=get(l,st-1);
            nw^=fl[i][l];
        }
        if(ed<r){
            if(fr[i][r]==-1) fr[i][r]=get(ed+1,r);
            nw^=fr[i][r];
        }
        res|=(1<<nw);
     }
     for(i=0;;++i)
      if(!((res>>i)&1)) return i;
}

inline int ask(int l,int r)
{
    int i,j,st,ed,res=0,nw;
    for(i=0;i<26;++i)
     if(qr[i][l]<=r){
        st=qr[i][l];ed=ql[i][r];
        nw=(w[i][id[st]]^w[i][id[ed]]);
        if(l<st){
            if(fl[i][l]==-1) fl[i][l]=ask(l,st-1);
            nw^=fl[i][l];
        }
        if(ed<r){
            if(fr[i][r]==-1) fr[i][r]=ask(ed+1,r);
            nw^=fr[i][r];
        }
        res|=(1<<nw);
     }
     for(i=0;;++i)
      if(!((res>>i)&1)) return i;
}

int main(){
    int i,j,alp,l,r;
    memset(fl,0xff,sizeof(fl));
    memset(fr,0xff,sizeof(fr));
    scanf("%s",s+1);
    n=strlen(s+1);
    for(i=1;i<=n;++i)
        id[i]=++num[s[i]-'a'];
    for(i=0;i<26;++i) ql[i][0]=0,qr[i][n+1]=n+1;
    for(i=1;i<=n;++i){
        for(j=0;j<26;++j) ql[j][i]=ql[j][i-1];
        ql[s[i]-'a'][i]=i;
    }
    for(i=n;i;--i){
        for(j=0;j<26;++j) qr[j][i]=qr[j][i+1];
        qr[s[i]-'a'][i]=i;
    }
    for(i=0;i<26;++i){
        for(cnt=0,j=1;j<=n;++j) if(s[j]-'a'==i) pos[++cnt]=j;
        for(j=1;j<cnt;++j)
          le[++tot]=L(pos[j+1]-pos[j]-1,pos[j],pos[j+1]);
    }
    sort(le+1,le+tot+1,cmp);//le+tot->le+tot+1 
    for(i=1;i<=tot;++i) if(le[i].r>le[i].l+1){
        j=le[i].r;
        w[s[j]-'a'][id[j]]=get(le[i].l+1,j-1);
    }
    for(i=0;i<26;++i) 
     for(j=2;j<=num[i];++j)
       w[i][j]^=w[i][j-1];
    scanf("%d",&m);
    for(;m;--m){
        scanf("%d%d",&l,&r);
        puts(ask(l,r)?"Alice":"Bob");
    }
}

猜你喜欢

转载自blog.csdn.net/corsica6/article/details/82387428