zoukankan      html  css  js  c++  java
  • [CSP-S模拟测试ex]题解

    爆零了。少特判见祖宗。还好这场不计入总分。

    考场上什么都没想。感觉考试状态又回到了两个月前。

    A.Antipalindrome

    手玩样例,不难发现题目中要求的合法串的充要条件是:对于任意$i in [2,n]$,有$ s[i] eq s[i-1] and s[i-1] eq s[i+1]$

    那么第一个位置有$m$种选择,第二个位置有$m-1$种,第三个位置往后都有$m-2$种。

    $ans=m(m-1)(m-2)^{n-2}$

    注意特判。如果判少会直接爆0。

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    const ll mod=1e9+7;
    int T;
    ll n,m;
    ll qpow(ll a,ll b)
    {
        ll res=1;a=a%mod;
        while(b)
        {
            if(b&1)res=res*a%mod;
            a=a*a%mod;
            b>>=1;
        }
        return res;
    }
    void work()
    {
        scanf("%lld%lld",&n,&m);
        m%=mod;
        if(m==1)
        {
            if(n==1)puts("1");
            else puts("0");
            return ;
        }
        if(n==1)
        {
            cout<<m<<endl;
            return ;
        }
        ll ans=m*(m-1)%mod;
        ans*=qpow(m-2,n-2),ans%=mod;
        cout<<ans<<endl;
    }
    int main()
    {
        scanf("%d",&T);
        while(T--)work();
        return 0;
    }
    

    B.Randomwalking

    明显的换根dp。设$f[x]$表示x的子树对答案的贡献,$g[x]$表示x子树之外的部分对答案的贡献。那么$f[]$可以先用一遍dfs求得,然后在换根过程中求$g[]$顺便统计答案。

    设$son[x]$为x的儿子数,显然这个要对根节点特判一下。那么可得$f[x]=a[x]+sum frac{f[y]}{son[x]}$,y是x的儿子。

    然后考虑怎么换根。设fa为x的父亲,方程为$g[x]=frac{g[fa]+(f[fa]-a[fa])*son[fa]-f[x]}{son[fa]}+a[fa]$。

    解释一下,$(f[fa]-a[fa])*son[fa]$

    相当与先还原出 $sum f[s]$    (s为fa的儿子,包括x),

    然后去掉$f[x]$的贡献,把剩下的作为x外部的点重新计算入$g[x]$。

    最后统计答案的时候要比较的是$frac{g[x]+(f[x]-a[x])*son[x]}{son[x]+1}+a[x]$,也相当与一个还原的过程。

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    using namespace std;
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    const int N=1e6+5;
    const double inf=9999999999999.0;
    typedef long long ll;
    int n,a[N];
    int to[N<<1],head[N],nxt[N<<1],tot,deg[N],minn;
    double dp[N],g[N],minx=inf;
    void add(int x,int y)
    {
        to[++tot]=y;
        nxt[tot]=head[x];
        head[x]=tot;
        deg[x]++;
    }
    void dfs1(int x,int f)
    {
        dp[x]=a[x];
        int d=f?deg[x]-1:deg[x];
        for(int i=head[x];i;i=nxt[i])
        {
            int y=to[i];
            if(y==f)continue;
            dfs1(y,x);
            dp[x]+=dp[y]/(1.0*d);
        }
    }
    void dfs2(int x,int f)
    {
        int df=(f==1?deg[f]:deg[f]-1);
        g[x]=(g[f]+(dp[f]-a[f])*df-dp[x])/df+a[f];
        double now=(g[x]+(dp[x]-a[x])*(deg[x]-1))/deg[x]+a[x];
        if(minx>now)minx=now,minn=x;
        for(int i=head[x];i;i=nxt[i])
            if(to[i]!=f)dfs2(to[i],x);
    }
    int main()
    {
        n=read();
        for(int i=1;i<=n;i++)
            a[i]=read();
        for(int i=1;i<n;i++)
        {
            int x=read(),y=read();
            add(x,y);add(y,x);
        }
        dfs1(1,0);
        minx=dp[1],minn=1;
        for(int i=head[1];i;i=nxt[i])
            dfs2(to[i],1);
        cout<<minn<<endl;
        return 0;
    }
    

    C.String

    记录一下每个原来的位置被翻转到了哪里,用并查集维护一定相同的位置对应关系。如果一个联通块中有一个确定了,那么就都确定了。对于剩下的'?',用26进制的思想逐位填。

    区间反转上Splay。卡常。

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #define re register
    using namespace std;
    
    const int L=1<<20|1;
    char buffer[L],*S,*T;
    #define getchar() ((S==T&&(T=(S=buffer)+fread(buffer,1,L,stdin),S==T))?EOF:*S++)
    
    const int N=5e5+5,inf=0x3f3f3f3f;
    typedef long long ll;
    int n,m,a[N],b[N],tot,fa[N],vis[N],unsu[N],cnt;
    ll K;
    char str[N],s[N];
    inline int rint()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    inline ll rll()
    {
        ll x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    inline void read(char x[])
    {
        char ch=getchar();int now=0;
        while(ch!='?'&&(ch>'z'||ch<'a'))ch=getchar();
        while(ch=='?'||(ch>='a'&&ch<='z'))x[++now]=ch,ch=getchar();
    }
    
    int findf(int x)
    {
        if(fa[x]==x)return x;
        return fa[x]=findf(fa[x]);
    }
    namespace Splay
    {
        int fa[N],son[N][3],size[N],key[N],v[N],type,root;
        inline bool judge(int x){return son[fa[x]][1]==x;}
        inline void up(int x){size[x]=size[son[x][0]]+size[son[x][1]]+1;}
        inline void down(int x)
        {
            if(x&&v[x])
            {
                v[son[x][0]]^=1;v[son[x][1]]^=1;
                swap(son[x][0],son[x][1]);v[x]=0;
            }
        }
        inline void rotate(int x)
        {
            int old=fa[x],oldf=fa[old],lr=judge(x);
            down(old);down(x);
            son[old][lr]=son[x][lr^1];
            fa[son[old][lr]]=old;
            son[x][lr^1]=old;fa[old]=x;
            fa[x]=oldf;
            if(oldf)son[oldf][son[oldf][1]==old]=x;
            up(old);up(x);
        }
        inline void splay(int x,int goal)
        {
            for(int f;(f=fa[x])!=goal;rotate(x))
                if(fa[f]!=goal)
                    rotate(judge(x)==judge(f)?f:x);
            if(!goal)root=x;
        }
        int build(int f,int l,int r)
        {
            if(l>r)return 0;
            int mid=l+r>>1,x=++type;
            key[x]=a[mid];fa[x]=f;
            v[x]=0;
            son[x][0]=build(x,l,mid-1);
            son[x][1]=build(x,mid+1,r);
            up(x);
            return x;
        }
        inline int getrank(int x)
        {
            int now=root;
            while(1)
            {
                down(now);
                if(x<=size[son[now][0]])now=son[now][0];
                else
                {
                    x-=size[son[now][0]]+1;
                    if(!x)return now;
                    now=son[now][1];
                }
            }
        }
        inline void rev(int l,int r)
        {
            l=getrank(l),r=getrank(r+2);
            splay(l,0);splay(r,l);
            down(root);
            v[son[son[root][1]][0]]^=1;
        }
        void print(int now)
        {
            down(now);
            if(son[now][0])print(son[now][0]);
            if(key[now]!=-inf&&key[now]!=inf)b[++tot]=key[now];
            if(key[son[now][1]])print(son[now][1]);
        }
    }
    int main()
    {
        n=rint();m=rint();K=rll();
        read(str);
        for(re int i=1;i<=n;i++)
            fa[i]=a[i+1]=i;
        a[1]=-inf;a[n+2]=inf;
        Splay::root=Splay::build(0,1,n+2);
        for(re int i=1;i<=m;i++)
        {
            int l=rint(),r=rint();
            Splay::rev(l,r);
        }
        Splay::print(Splay::root);
        /*for(int i=1;i<=n;i++)
            cout<<b[i]<<' ';
        puts(" ");*/
        for(re int i=1;i<=n;i++)
        {
            int fx=findf(b[i]),fy=findf(i);
            if(fx==fy)continue;
            if(str[fy]=='?')str[fy]=str[fx];
            fa[fx]=fy;
        }
        for(re int i=1;i<=n;i++)
        {
            int fx=findf(i);
            s[i]=str[fx];
            if(s[i]=='?'&&!vis[fx])vis[fx]=1,unsu[++cnt]=fx;
        }
        K--;int now=cnt;
        while(K)
        {
            str[unsu[now]]='a'+K%26;
            now--;
            K/=26;
        }
        while(now>0)str[unsu[now]]='a',now--;
        for(re int i=1;i<=n;i++)
        {
            if(s[i]=='?')s[i]=str[findf(i)];
            putchar(s[i]);
        }
        putchar('
    ');
        return 0;
    }
    
  • 相关阅读:
    回调函数(C语言)
    main函数的参数(一)
    术语,概念
    [LeetCode] Invert Binary Tree
    关于overload和override
    第一个只出现一次的字符
    Manacher算法----最长回文子串
    C++对象模型
    回文判断
    字符串转换成整数
  • 原文地址:https://www.cnblogs.com/Rorschach-XR/p/11598355.html
Copyright © 2011-2022 走看看