首页 > 其他分享 >CF1785

CF1785

时间:2023-02-06 16:11:23浏览次数:44  
标签:CF1785 aa bb && ans ord reg

A

略,具体见 C。

B

这题卡了我一会,写起来又花了挺长一段时间的,水平还是不够!

贪心一下,优先取贡献为 \(2\) 的,其次取贡献为 \(1\) 的,看上去就很对。

Code:

#include<bits/stdc++.h>
#define IL inline
#define reg register
#define N 100100
IL int read()
{
    reg int x=0; reg char ch=getchar();
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x;
}

std::vector<int>v[4][4][4];
int n,ans,ord[5000500][4];
char s[N];
const char h[]={'w','i','n'};

IL void work()
{
    n=read();
    for(reg int a=4,b,c;a--;)for(b=4;b--;)for(c=4;c--;)v[a][b][c].clear();
    for(reg int i=1,a,b,c;i<=n;++i)
    {
        scanf("%s",s),a=b=c=0;
        if(s[0]=='w')++a; else if(s[0]=='i')++b; else ++c;
        if(s[1]=='w')++a; else if(s[1]=='i')++b; else ++c;
        if(s[2]=='w')++a; else if(s[2]=='i')++b; else ++c;
        v[a][b][c].push_back(i);
    }
    ans=0;
    while(1)
    {
        reg bool flag=0;
        for(reg int a=4,b,c;a--;)for(b=4;b--;)for(c=4;c--;)if((a!=b||b!=c)&&!v[a][b][c].empty())flag=1;
        if(!flag)break;
        for(reg int a=4,b,c,aa,bb,cc,x,y;a--;)for(b=4-a;b--;)if(v[a][b][c=3-a-b].size()&&(!a||!b||!c))
            for(aa=4;aa--;)for(bb=4-aa;bb--;)if(v[aa][bb][cc=3-aa-bb].size())
            {
                if(a==aa&&b==bb&&c==cc)continue;
                x=v[a][b][c].back(),y=v[aa][bb][cc].back(),v[a][b][c].pop_back(),v[aa][bb][cc].pop_back();
                if(!a&&aa>1&&b>1&&!bb)
                {
                    ++ans,ord[ans][0]=x,ord[ans][1]=0,ord[ans][2]=y,ord[ans][3]=1;
                    v[a+1][b-1][c].push_back(x),v[aa-1][bb+1][cc].push_back(y);
                    goto skip;
                }
                if(!a&&aa>1&&c>1&&!cc)
                {
                    ++ans,ord[ans][0]=x,ord[ans][1]=0,ord[ans][2]=y,ord[ans][3]=2;
                    v[a+1][b][c-1].push_back(x),v[aa-1][bb][cc+1].push_back(y);
                    goto skip;
                }
                if(!b&&bb>1&&c>1&&!cc)
                {
                    ++ans,ord[ans][0]=x,ord[ans][1]=1,ord[ans][2]=y,ord[ans][3]=2;
                    v[a][b+1][c-1].push_back(x),v[aa][bb-1][cc+1].push_back(y);
                    goto skip;
                }
                v[a][b][c].push_back(x),v[aa][bb][cc].push_back(y);
            }
        for(reg int a=4,b,c,aa,bb,cc,x,y;a--;)for(b=4-a;b--;)if(v[a][b][c=3-a-b].size()&&(!a||!b||!c))
            for(aa=4;aa--;)for(bb=4-aa;bb--;)if(v[aa][bb][cc=3-aa-bb].size()&&(!aa||!bb||!cc))
            {
                if(a==aa&&b==bb&&c==cc)continue;
                x=v[a][b][c].back(),y=v[aa][bb][cc].back(),v[a][b][c].pop_back(),v[aa][bb][cc].pop_back();
                if(aa&&b&&(!a&&b>1||!bb&&aa>1))
                {
                    ++ans,ord[ans][0]=x,ord[ans][1]=0,ord[ans][2]=y,ord[ans][3]=1;
                    v[a+1][b-1][c].push_back(x),v[aa-1][bb+1][cc].push_back(y);
                    goto skip;
                }
                if(aa&&c&&(!a&&c>1||!cc&&aa>1))
                {
                    ++ans,ord[ans][0]=x,ord[ans][1]=0,ord[ans][2]=y,ord[ans][3]=2;
                    v[a+1][b][c-1].push_back(x),v[aa-1][bb][cc+1].push_back(y);
                    goto skip;
                }
                if(bb&&c&&(!b&&c>1||!cc&&bb>1))
                {
                    ++ans,ord[ans][0]=x,ord[ans][1]=1,ord[ans][2]=y,ord[ans][3]=2;
                    v[a][b+1][c-1].push_back(x),v[aa][bb-1][cc+1].push_back(y);
                    goto skip;
                }
                v[a][b][c].push_back(x),v[aa][bb][cc].push_back(y);
            }
        skip:;
    }
    printf("%d\n",ans);
    for(reg int i=1;i<=ans;++i)printf("%d %c %d %c\n",ord[i][0],h[ord[i][3]],ord[i][2],h[ord[i][1]]);
}

main()
{
    for(reg int t=read();t--;work());
}

C

“给你们展示一下,什么是教科书一般的亵渎。”

这场先开的这题,状态没起来,WA 了好多发,罚时直接起飞了!

首先考虑最小次数怎么求,有一个简单贪心。

去维护一下哪些怪是用于凑亵渎的等差数列的,可以增量算出全局打几。

在值域上维护比较方便。

Code:

#include<bits/stdc++.h>
#define IL inline
#define reg register
#define int long long
#define N 200200
IL int read()
{
    reg int x=0; reg char ch=getchar();
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x;
}

int n,all,ans,cnt,x[N];

#define ls (o<<1)
#define rs (o<<1|1)
#define mid (l[o]+r[o]>>1)

int l[N<<2],r[N<<2],tag[N<<2],mn[N<<2],pos[N<<2];

IL void upd(reg int o,reg int k){mn[o]+=k,tag[o]+=k;}
IL void pushup(reg int o){if(mn[ls]<=mn[rs])pos[o]=pos[ls],mn[o]=mn[ls]; else pos[o]=pos[rs],mn[o]=mn[rs];}
IL void pushdown(reg int o){if(tag[o])upd(ls,tag[o]),upd(rs,tag[o]),tag[o]=0;}

void build(reg int o,reg int L,reg int R)
{
    l[o]=L,r[o]=R,mn[o]=pos[o]=L,tag[o]=0;
    if(L<R)build(ls,L,mid),build(rs,mid+1,R);
}

void modify(reg int o,reg int L,reg int R,reg int k)
{
    if(L<=l[o]&&r[o]<=R)return upd(o,k);
    if(L>r[o]||l[o]>R)return;
    pushdown(o),modify(ls,L,R,k),modify(rs,L,R,k),pushup(o);
}

IL void work()
{
    n=read(),all=ans=cnt=0,build(1,1,n);
    for(reg int i=1;i<=n;++i)x[i]=read();
    for(reg int i=1,p;i<=n;++i)
    {
        all+=x[i],modify(1,x[i],n,-1);
        if(mn[1]<0)p=pos[1],modify(1,p,n,1),ans+=p; else ++cnt;
        printf("%lld ",all-ans-cnt*(cnt+1)/2);
    }
    puts("");
}

main()
{
    for(reg int t=read();t--;work());
}

D

这场除了 A 以外最简单的题。

考虑最终的对决一定是 \(1\ x(x\neq 1)\),那么有 \(1\) 所在的那棵子树的所有 \(2^{n-1}\) 个位置都不会有 Wooden Spoon

继续考虑其他位置,则会有一个递归的不断删一半位置的操作。

直接进行 dp 就可以了。

Code:

#include<bits/stdc++.h>
#define IL inline
#define reg register
#define mod 998244353
IL int read()
{
    reg int x=0; reg char ch=getchar();
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x;
}

IL int Add(reg int x,reg int y){return x+y<mod?x+y:x+y-mod;}
IL void Pls(reg int &x,reg int y){x=Add(x,y);}
IL int Mul(reg int x,reg int y){reg long long r=1ll*x*y; return r<mod?r:r%mod;}

int n,f[1<<20|5][22],ans[1<<20|5],fac[1<<20|5],full;

main()
{
    n=read(),full=1<<n,f[0][0]=fac[0]=1;
    for(reg int i=1;i<=full;++i)fac[i]=Mul(fac[i-1],i);
    for(reg int i=0,j,w,x;i<full;++i)for(j=0;j<=n;++j)if(w=f[i][j])
    {
        x=1<<n-j,Pls(f[i+1][j],Mul(w,full-x-i));
        if(j==n)Pls(ans[i+1],Mul(w,Mul(x,fac[full-i-1]))); else Pls(f[i+1][j+1],Mul(w,x));
    }
    for(reg int i=1;i<=full;++i)printf("%d\n",ans[i]);
}

E

赛时常数没写好,优化过状态数的代码都过不去,好气啊!

考虑 dp of dp。

维护 \(\emptyset,\left\{a\right\},\left\{b\right\},\left\{ab\right\}\) 走到的状态以及 Alice 与 Bob 的获胜局数之差。统计答案的时候有一个基环森林。

这样的状态数量是 \(9\times 10^5\) 级别的,好像说是直接可以过了。

但可以再优化,观察到 \(\left\{a\right\},\left\{b\right\}\) 不会同时出现在最终的基环森林中 \(\emptyset\) 所在的那个基环数上。

可以进一步地压缩状态数。这个优化看起来非常强,但实际的效果并不显著,仅将状态数优化到了 \(511752\)。(但以我的答辩常数仍旧无法通过)

Code(赛时被卡常版本):

#include<bits/stdc++.h>
#define IL inline
#define reg register
#define mod 998244353
#define N 220
IL int read()
{
    reg int x=0; reg char ch=getchar();
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x;
}
    
IL int Add(reg int x,reg int y){return x+y<mod?x+y:x+y-mod;}
IL int Sub(reg int x,reg int y){return x<y?x-y+mod:x-y;}
IL void Pls(reg int &x,reg int y){x=Add(x,y);}
IL void Dec(reg int &x,reg int y){x=Sub(x,y);}
IL int Mul(reg int x,reg int y){reg long long r=1ll*x*y; return r<mod?r:r%mod;}
    
int n;
char s[N];
bool ban[4];
    
#define ull unsigned long long
const ull B1=533,B2=20;
    
struct Node{int x[4],y[4];}p,q;
std::unordered_map<ull,int>f[2];
    
IL Node back(reg ull h)
{
    reg Node tp;
    for(reg int i=4;i--;)if(!ban[i])tp.y[i]=h%B1-n,h/=B1;
    for(reg int i=4;i--;)if(!ban[i])tp.x[i]=h%B2,h/=B2;
    return tp;
}
    
IL ull hash(reg Node &p)
{
    reg ull h=0;
    for(reg int i=0;i<4;++i)if(!ban[i])h=h*B2+p.x[i];
    for(reg int i=0;i<4;++i)if(!ban[i])h=h*B1+n+p.y[i];
    return h;
}
    
int ch[4][2],de[4][2],ans1,ans2,ans3;
bool vis[4];
    
IL void clear(reg std::unordered_map<ull,int>&a){reg std::unordered_map<ull,int>b; std::swap(a,b);}
    
main()
{
    scanf("%s",s+1),n=strlen(s+1);
    ch[0][0]=1,ch[0][1]=2,de[1][0]=1,ch[1][1]=3,ch[2][0]=3,de[2][1]=-1,de[3][0]=1,de[3][1]=-1;
    
    reg int a=0,b=1;
    for(reg int i=4;i--;)p.x[i]=i,p.y[i]=0; ban[1]=1;
    f[a][hash(p)]=1;
    for(reg int i=1,j,w;i<=n;++i,a^=1,b^=1)
    {
        clear(f[b]);
        for(reg auto t:f[a])
        {
            p=back(t.first),w=t.second;
            if(!w)continue;
            if(s[i]!='b')
            {
                for(j=4;j--;)q.x[j]=ch[p.x[j]][0],q.y[j]=p.y[j]+de[p.x[j]][0];
                Pls(f[b][hash(q)],w);
            }
            if(s[i]!='a')
            {
                for(j=4;j--;)q.x[j]=ch[p.x[j]][1],q.y[j]=p.y[j]+de[p.x[j]][1];
                Pls(f[b][hash(q)],w);
            }
        }
    }
    for(reg auto t:f[a])
    {
        p=back(t.first),memset(vis,0,sizeof(vis));
        reg int u=0,s=0,k=0;
        while(!vis[u])vis[u]=1,s+=p.y[u],u=p.x[u]; if(vis[1])continue;
        vis[u]=0,k=p.y[u],u=p.x[u];
        while(vis[u])k+=p.y[u],u=p.x[u];
        if(k>0)Pls(ans1,t.second);
        else if(k<0)Pls(ans3,t.second);
        else Pls(ans2,t.second);
    }
    clear(f[a]),ban[1]=0;
    
    for(reg int i=4;i--;)p.x[i]=i,p.y[i]=0; ban[2]=1;
    f[a][hash(p)]=1;
    for(reg int i=1,j,w;i<=n;++i,a^=1,b^=1)
    {
        clear(f[b]);
        for(reg auto t:f[a])
        {
            p=back(t.first),w=t.second;
            if(!w)continue;
            if(s[i]!='b')
            {
                for(j=4;j--;)q.x[j]=ch[p.x[j]][0],q.y[j]=p.y[j]+de[p.x[j]][0];
                Pls(f[b][hash(q)],w);
            }
            if(s[i]!='a')
            {
                for(j=4;j--;)q.x[j]=ch[p.x[j]][1],q.y[j]=p.y[j]+de[p.x[j]][1];
                Pls(f[b][hash(q)],w);
            }
        }
    }
    for(reg auto t:f[a])
    {
        p=back(t.first),memset(vis,0,sizeof(vis));
        reg int u=0,s=0,k=0;
        while(!vis[u])vis[u]=1,s+=p.y[u],u=p.x[u]; if(vis[2])continue;
        vis[u]=0,k=p.y[u],u=p.x[u];
        while(vis[u])k+=p.y[u],u=p.x[u];
        if(k>0)Pls(ans1,t.second);
        else if(k<0)Pls(ans3,t.second);
        else Pls(ans2,t.second);
    }
    clear(f[a]),ban[2]=0;
    
    for(reg int i=4;i--;)p.x[i]=i,p.y[i]=0; ban[1]=ban[2]=1;
    f[a][hash(p)]=1;
    for(reg int i=1,j,w;i<=n;++i,a^=1,b^=1)
    {
        clear(f[b]);
        for(reg auto t:f[a])
        {
            p=back(t.first),w=t.second;
            if(!w)continue;
            if(s[i]!='b')
            {
                for(j=4;j--;)q.x[j]=ch[p.x[j]][0],q.y[j]=p.y[j]+de[p.x[j]][0];
                Pls(f[b][hash(q)],w);
            }
            if(s[i]!='a')
            {
                for(j=4;j--;)q.x[j]=ch[p.x[j]][1],q.y[j]=p.y[j]+de[p.x[j]][1];
                Pls(f[b][hash(q)],w);
            }
        }
    }
    for(reg auto t:f[a])
    {
        p=back(t.first),memset(vis,0,sizeof(vis));
        reg int u=0,s=0,k=0;
        while(!vis[u])vis[u]=1,s+=p.y[u],u=p.x[u]; if(vis[1])continue;
        vis[u]=0,k=p.y[u],u=p.x[u];
        while(vis[u])k+=p.y[u],u=p.x[u];
        if(k>0)Dec(ans1,t.second);
        else if(k<0)Dec(ans3,t.second);
        else Dec(ans2,t.second);
    }
    
    printf("%d\n%d\n%d\n",ans1,ans2,ans3);
}

F

咕咕咕。

标签:CF1785,aa,bb,&&,ans,ord,reg
From: https://www.cnblogs.com/Nesraychan/p/17095712.html

相关文章