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 \tbinom{i-1}{k-1} k! (n-k)!\]

\(\tbinom{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;
}

猜你喜欢

转载自www.cnblogs.com/yzhang-rp-inf/p/11365923.html