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;
}