zoukankan      html  css  js  c++  java
  • JXOI2018简要题解

    T1排序问题

    考虑如果所有数都不同,那么一定只有一种方案可行,需要(n!)

    如果有数相同,考虑强制大小关系,最后除上每个相同数之内的排列个数

    考虑如何加入新的数,明显是越平均越好,模拟一下即可

    复杂度为(O(Tn log n))

    #include <bits/stdc++.h>
    #define N 200005
    #define M 10000005
    #define mod 998244353
    #define getchar nc
    using namespace std;
    inline char nc(){
        static char buf[100000],*p1=buf,*p2=buf;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
    }
    inline int read()
    {
        register int x=0,f=1;register char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
        return x*f;
    }
    inline void write(register int x)
    {
        if(!x)putchar('0');if(x<0)x=-x,putchar('-');
        static int sta[20];register int tot=0;
        while(x)sta[tot++]=x%10,x/=10;
        while(tot)putchar(sta[--tot]+48);
    }
    inline int power(register int a,register int b)
    {
        int res=1;
        while(b)
        {
            if(b&1)
                res=1ll*res*a%mod;
            a=1ll*a*a%mod;
            b>>=1;
        }
        return res;
    }
    int fac[N+M];
    int T,n,m,l,r,ans,a[N],b[N],c[N],t[N];
    inline void solve()
    {
        n=read(),m=read(),l=read(),r=read();
        for(register int i=1;i<=n;++i)
            a[i]=read();
        ans=fac[n+m];
        int t1=0,t2=0,top=0;
        sort(a+1,a+1+n);
        for(register int i=1;i<=n;++i)
            if(l<=a[i]&&a[i]<=r)
                b[++t1]=a[i];
            else
                c[++t2]=a[i];
        b[t1+1]=c[t2+1]=0;
        for(register int i=2,res=1;i<=t2+1;++i)
            if(c[i]!=c[i-1])
                ans=1ll*ans*power(fac[res],mod-2)%mod,res=1;
            else
                ++res;
        for(register int i=2,res=1;i<=t1+1;++i)
            if(b[i]!=b[i-1])
                t[++top]=res,res=1;
            else
                ++res;
        sort(t+1,t+top+1);
        int lef=r-l+1-top,nw=0,i=1;
        for(;i<=top;++i)
        {
            if(1ll*lef*(t[i]-nw)<=m)
                m-=1ll*lef*(t[i]-nw),nw=t[i],++lef;
            else 
                break;
        }
        nw+=m/lef;
        m%=lef;
        ans=1ll*ans*power(power(fac[nw],mod-2),lef-m)%mod;
        ans=1ll*ans*power(power(fac[nw+1],mod-2),m)%mod;
        for(;i<=top;++i)
            ans=1ll*ans*power(fac[t[i]],mod-2)%mod;
        write(ans),puts("");
    }
    int main()
    {
        fac[0]=1;
        for(register int i=1;i<N+M;++i)
            fac[i]=1ll*fac[i-1]*i%mod;
        T=read();
        while(T--)
            solve();
    	return 0;
    }
    

    T2游戏

    根据倍数关系珂以建出图,举个栗子:1,2,3要向6连边,1,2,4要向8连边……,这个珂以线性筛解决

    这样我们珂以得出结论,要把所有度数为0的点选上,设这个数为(k),则

    [Ans=sum_{i=k}^n i binom{i-1}{k-1} k! (n-k)! ]

    ( binom{i-1}{k-1})表示第(i)个取的点是度数为0的点,前面(i-1)个取的点要有(k-1)个度数为0的点的方案数,(k!)((n-k)!)表示度数是否为0的之内的排序方案数

    暴力计算一下即可,复杂度为(O(n))

    #include <bits/stdc++.h>
    #define N 10000005
    #define mod 1000000007
    #define getchar nc
    using namespace std;
    inline char nc(){
        static char buf[100000],*p1=buf,*p2=buf;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
    }
    inline int read()
    {
        register int x=0,f=1;register char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
        return x*f;
    }
    inline void write(register int x)
    {
        if(!x)putchar('0');if(x<0)x=-x,putchar('-');
        static int sta[20];register int tot=0;
        while(x)sta[tot++]=x%10,x/=10;
        while(tot)putchar(sta[--tot]+48);
    }
    inline int power(register int a,register int b)
    {
        int res=1;
        while(b)
        {
            if(b&1)
                res=1ll*res*a%mod;
            a=1ll*a*a%mod;
            b>>=1;
        }
        return res;
    }
    int l,r,n,ans,cnt;
    int ispr[N],pr[N],tot,fac[N],invf[N];
    inline void init()
    {
        ispr[1]=pr[1]=1;
        if(l==1)
        {
            cnt=1;
            return;
        }
        for(register int i=2;i<=r;++i)
        {
            if(!ispr[i])
                pr[++tot]=i,cnt+=(i>=l);
            for(register int j=1;j<=tot&&pr[j]*i<=r;++j)
            {
                ispr[pr[j]*i]=1;
                if(i<l&&i*pr[j]>=l)
                    ++cnt;
                if(i%pr[j]==0)
                    break;
            }
        }
    }
    int main()
    {
        l=read(),r=read(),n=r-l+1;
        init();
        fac[0]=1;
        for(register int i=1;i<=n;++i)
            fac[i]=1ll*fac[i-1]*i%mod;
        invf[n]=power(fac[n],mod-2);
        for(register int i=n-1;i>=0;--i)
            invf[i]=1ll*invf[i+1]*(i+1)%mod;
        for(register int i=cnt;i<=n;++i)
            ans=(0ll+ans+1ll*i*fac[i-1]%mod*invf[i-cnt]%mod)%mod;
        write(1ll*ans*invf[cnt-1]%mod*fac[cnt]%mod*fac[n-cnt]%mod);
    	return 0;
    }
    

    T3守卫

    挺神奇的一道题,估计考场上就要因这题而200pts退役了

    (f[l][r])表示([l,r])的答案,随便转移转移(看了程序就能懂了),复杂度为(O(n^2))

    #include <bits/stdc++.h>
    #define N 5005
    #define getchar nc
    using namespace std;
    inline char nc(){
        static char buf[100000],*p1=buf,*p2=buf;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
    }
    inline int read()
    {
        register int x=0,f=1;register char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
        return x*f;
    }
    inline void write(register int x)
    {
        if(!x)putchar('0');if(x<0)x=-x,putchar('-');
        static int sta[20];register int tot=0;
        while(x)sta[tot++]=x%10,x/=10;
        while(tot)putchar(sta[--tot]+48);
    }
    int n,h[N],see[N][N],f[N][N],ans;
    int main()
    {
        n=read();
        for(register int i=1;i<=n;++i)
            h[i]=read();
        for(register int i=1,l=0;i<=n;++i,l=i-1)
            for(double mx=1e9;l>=1;--l)
                if(1.0*(h[i]-h[l])/(i-l)<mx)
                    mx=1.0*(h[i]-h[l])/(i-l),see[l][i]=1;
        for(register int r=1;r<=n;++r)
            for(register int l=r,s=1,las=l;l>=1;--l)
            {
                if(see[l][r])
                {
                    if(!see[l+1][r])
                        s+=min(f[l+1][las],f[l+1][las+1]);
                    f[l][r]=s;
                }
                else
                {
                    if(see[l+1][r])
                        las=l;
                    f[l][r]=s+min(f[l][las],f[l][las+1]);
                }
                ans^=f[l][r];
            }
        write(ans);
    	return 0;
    }
    
  • 相关阅读:
    BZOJ1610: [Usaco2008 Feb]Line连线游戏
    BZOJ4554: [Tjoi2016&Heoi2016]游戏
    BZOJ3174: [Tjoi2013]拯救小矮人
    BZOJ3192: [JLOI2013]删除物品
    BZOJ3156: 防御准备
    BZOJ3875: [Ahoi2014&Jsoi2014]骑士游戏
    BZOJ 1597: [Usaco2008 Mar]土地购买
    洛谷 P3375 【模板】KMP字符串匹配
    洛谷 P3370 【模板】字符串哈希
    BZOJ 1083 繁忙的都市
  • 原文地址:https://www.cnblogs.com/yzhang-rp-inf/p/11365923.html
Copyright © 2011-2022 走看看