T1 fantastic
题意:求一个矩阵在模意义下的逆
一个结论:一个矩阵A在模p意义下有逆元,当且仅当
gcd(|A|,m)=1
,其中
|A|
是矩阵A的行列式的值(PS:本人不会证)
题解和代码稍后贴
T2 allonsy
题解:对于给定的一个t,可以直接求期望
f[n]=∑ni=0Cinpi(1−p)n−i×|n−2×i|
O(n)
预处理出阶乘,阶乘的逆元,p的幂次和1-p的幂次即可
总复杂度
O(n)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define LL long long
const int N=50010;
LL n,q,mod,p;
LL ans;
LL fac[N<<1],inv[N<<1],q_pow[N<<1],Q_pow[N<<1];
LL ksm(LL a,LL b)
{
LL ret=1;
while(b)
{
if(b&1) ret=(ret*a)%mod;
a=a*a%mod;
b>>=1;
}
return ret%mod;
}
void init()
{
p=(1-q+mod)%mod;
q_pow[0]=Q_pow[0]=fac[0]=1;
for(int i=1;i<=N;i++)
{
q_pow[i]=q_pow[i-1]*q%mod;
fac[i]=fac[i-1]*i%mod;
Q_pow[i]=Q_pow[i-1]*p%mod;
}
inv[N]=ksm(fac[N],mod-2);
for(int i=N-1;i>=0;i--) inv[i]=inv[i+1]*(i+1)%mod;
}
LL C(LL a,LL b)
{
return fac[a]*inv[b]%mod*inv[a-b]%mod;
}
int main()
{
freopen("allonsy.in","r",stdin);
freopen("allonsy.out","w",stdout);
scanf("%lld%lld%lld",&n,&q,&mod);
init();
for(LL i=0;i<=n;i++)
ans=(ans+Q_pow[n-i]*q_pow[i]%mod*abs(n-2*i)%mod*C(n,i))%mod;
printf("%lld\n",ans%mod);
return 0;
}
T3 geronimo
题解:对于任意一个位置的一个数,经过若干次置换之后一定还会回到这个数,那么对于所有的数,他们都要回到原位置的次数就应该是所有数字回到原地的lcm,每一个置换群里需要的次数是一样的,我们只需要算一次,考虑到数字比较大,可以通过质因数分解,最后合并求lcm
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define LL long long
LL a[500010],n,mod,p[500010],anss=1,cnt;
bool vis[500010];
const int N=500050;
LL prime[N<<2],pcnt;
bool is[N<<2];
int xishu[N],ans[N],tot,maxn;
void get_prime()
{
for(int i=2;i<=N;i++)
{
if(!is[i])
prime[++pcnt]=i;
for(int j=1;j<=pcnt;j++)
{
if(i*prime[j]>N) break;
is[i*prime[j]]=1;
if(i%prime[j]==0) break;
}
}
}
void dfs(int x)
{
cnt++;
vis[x]=1;
if(!vis[a[x]]) dfs(a[x]);
}
LL ksm(LL a,LL b)
{
LL ret=1;
while(b)
{
if(b&1) ret=(ret*a)%mod;
a=(a*a)%mod;
b>>=1;
}
return ret;
}
int main()
{
freopen("geronimo.in","r",stdin);
freopen("geronimo.out","w",stdout);
get_prime();
scanf("%lld%lld",&n,&mod);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
for(int i=1;i<=n;i++)
if(!vis[i])
{
cnt=0;
dfs(i);
memset(xishu,0,sizeof(xishu));
for(int j=1;j<=pcnt;j++)
{
while(cnt%prime[j]==0) xishu[j]++,cnt/=prime[j];
if(cnt==1) {tot=j;break;}
}
maxn=max(maxn,tot);
for(int i=1;i<=tot;i++)
ans[i]=max(ans[i],xishu[i]);
}
for(int i=1;i<=maxn;i++)
if(ans[i]) anss=ksm(prime[i],ans[i])*anss%mod;
printf("%lld\n",anss);
return 0;
}//代码是后来重构的,所以写的比较丑勿怪QAQ
为什么这套题都是送命数学题