大意
求 n n n的排列了交换为升序的最小交换次数的期望
思路
两种思路
- 暴力打表找规律
- 动态规划
第一种只需要打一个 b f s bfs bfs+ h a s h hash hash找出规律即可,参考代码:
#include<cstdio>
#include<queue>
#define p 10000007
using namespace std;int n,ans;
struct node{int a[11],bs;}begin;
struct hash
{
long long h[p];
inline int find(long long x)
{
int y=x%p;
while(h[y]&&h[y]!=x) (y+=1)%=p;
return y;
}
inline void push(node x)
{
long long t=0;
for(register int i=1;i<=n;i++) t=(t<<3)+(t<<1)+x.a[i];
h[find(t)]=t;
return;
}
inline bool check(node x)
{
long long t=0;
for(register int i=1;i<=n;i++) t=(t<<3)+(t<<1)+x.a[i];
return h[find(t)]==t;
}
}h;
inline void bfs()
{
queue<node>q;
q.push(begin);h.push(begin);
while(q.size())
{
node x=q.front();q.pop();
for(register int i=1;i<n;i++)
for(register int j=i+1;j<=n;j++)
{
node y=x;
swap(y.a[i],y.a[j]);
y.bs=x.bs+1;
if(!h.check(y))
{
h.push(y);
q.push(y);
ans+=y.bs;
}
}
}
return;
}
signed main()
{
scanf("%d",&n);begin.bs=0;
for(register int i=1;i<=n;i++) begin.a[i]=i;
bfs();
printf("%d",ans);
}
第二种
d
p
dp
dp思路也很明显,除了最后是
n
n
n其它所有的交换次数都会变多
a
[
i
]
=
a
[
i
−
1
]
×
i
+
(
i
−
1
)
×
(
i
−
1
)
!
a[i]=a[i-1]\times i+(i-1)\times (i-1)!
a[i]=a[i−1]×i+(i−1)×(i−1)!
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#define wyc 998244353
using namespace std;
long long a[10000001],jc,inv[10000001],n,t;
inline long long ksm(long long x,long long y)
{
long long ans;
for(ans=1;y;(x*=x)%=wyc,y>>=1) if(y&1)(ans*=x)%=wyc;
return ans;
}
inline long long read()
{
char c;int f=0;
while(c=getchar(),c<48||c>57);f=(f<<3)+(f<<1)+c-48;
while(c=getchar(),c>47&&c<58) f=(f<<3)+(f<<1)+c-48;
return f;
}
inline void write(long long x){if(x>9)write(x/10);putchar(x%10+48);return;}
signed main()
{
a[1]=0;a[2]=1;jc=2;inv[0]=inv[1]=1;inv[2]=2;
for(register int i=3;i<=10000000;i++)
{
a[i]=(a[i-1]*i%wyc+(i-1)*jc%wyc)%wyc;
(jc*=i)%=wyc;
(inv[i]=inv[i-1]*i)%=wyc;
}
t=read();
while(t--)
{
n=read();
write((a[n]*ksm(inv[n],wyc-2))%wyc);putchar(10);
}
}
代码2
#include<cstdio>
#include<cstring>
#include<algorithm>
#define wyc 998244353
using namespace std;
long long a[10000001],jc,inv[10000001],n,t;
inline long long ksm(long long x,long long y)
{
long long ans;
for(ans=1;y;(x*=x)%=wyc,y>>=1) if(y&1)(ans*=x)%=wyc;
return ans;
}
inline long long read()
{
char c;int f=0;
while(c=getchar(),c<48||c>57);f=(f<<3)+(f<<1)+c-48;
while(c=getchar(),c>47&&c<58) f=(f<<3)+(f<<1)+c-48;
return f;
}
inline void write(long long x){if(x>9)write(x/10);putchar(x%10+48);return;}
signed main()
{
a[1]=0;a[2]=1;jc=2;inv[0]=inv[1]=1;inv[2]=2;
for(register int i=3;i<=10000000;i++)
{
a[i]=(a[i-1]*i%wyc+(i-1)*jc%wyc)%wyc;
(jc*=i)%=wyc;
}
inv[10000000]=ksm(jc,wyc-2);//O(n)倒序求逆元
for(register int i=9999999;i>0;i--) (inv[i]=inv[i+1]*(i+1)%wyc)%=wyc;
t=read();
while(t--)
{
n=read();
write((a[n]*inv[n]%wyc)%wyc);putchar(10);
}
}