链接
题解
每条边能可以连、可以不连,其实就可以看作完全图每条边可以涂蓝色可以涂红色
那么这个题又变成了等价类计数问题
枚举边的置换的话,是不对的,因为直接枚举边的置换会导致本来有公共端点的边置换之后失去了公共顶点
直接枚举点的置换,就可以得到一个边的置换,而且是合法的所有边的合法置换都可以对应到一个点的置换
好,现在我枚举了一个点的置换
现在我们不是要使用 b u r n s i d e burnside burnside吗,那我就要求出一个点的置换对应的边置换的等价类数目(假设是m),然后把 2 m 2^m 2m加入答案。
怎么求呢?
边有两种,第一种是两个顶点都在同一个环内(我说的是置换里的环),可以发现对于一个大小为 s s s的环,这种等价类共有 ⌊ s 2 ⌋ \lfloor \frac{s}{2} \rfloor ⌊2s⌋个(其实很好数,间隔为 1 1 1的、间隔为 2 2 2的、间隔为 3 3 3的…间隔为 ⌊ s 2 ⌋ \lfloor \frac{s}{2} \rfloor ⌊2s⌋的);然后再就两个端点分属两个环的边,假设第一个环大小为 a a a,另一个大小为 b b b,那么我先固定边的一头在第一个环的某个点,另一头在第二个环的某个点,然后开始“转”,每次每个换上的点“转”到下一个点,最后肯定会转回来,并且一共经过了 l c m ( a , b ) lcm(a,b) lcm(a,b)个点,这是显而易见的,那么一共有 a b ab ab条边,我可以得到等价类的数目为 a b l c m ( a , b ) = g c d ( a , b ) \frac{ab}{lcm(a,b)} = gcd(a,b) lcm(a,b)ab=gcd(a,b)
对所有的置换的 2 m 2^m 2m求和( m m m代表等价类数目),然后除以 n ! n! n!就是答案
但是我肯定不能枚举置换啊,那怎么办?其实很简单,枚举整数拆分,算出 m m m,然后再用组合数学的知识算出这种拆分对应了多少种置换即可
这样的话好像最大数据还是要跑好几秒,但是一看 N N N那么小,我直接打个表交上去不就完了
代码
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define iinf 0x3f3f3f3f
#define linf (1ll<<60)
#define eps 1e-8
#define maxn 300010
#define cl(x) memset(x,0,sizeof(x))
#define rep(i,a,b) for(i=a;i<=b;i++)
#define em(x) emplace(x)
#define emb(x) emplace_back(x)
#define emf(x) emplace_front(x)
#define fi first
#define se second
#define de(x) cerr<<#x<<" = "<<x<<endl
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
ll read(ll x=0)
{
ll c, f(1);
for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
for(;isdigit(c);c=getchar())x=x*10+c-0x30;
return f*x;
}
#define mod 997ll
ll fact[maxn], _fact[maxn], pow2[maxn], inv[maxn], ans=0, N, v[maxn], tot;
void dfs(ll res, ll mn)
{
ll i, j;
if(res==0)
{
ll cnt = fact[N], sum=0, t=0;
// rep(i,1,tot)printf("%lld ",v[i]); putchar(10);
rep(i,1,tot)(cnt*=inv[v[i]])%=mod;
rep(i,1,tot)
{
if(v[i]==v[i-1])t++;
else
{
(cnt*=_fact[t])%=mod;
t=1;
}
}
(cnt*=_fact[t])%=mod;
rep(i,1,tot)sum+=v[i]/2;
rep(i,1,tot)rep(j,i+1,tot)sum+=__gcd(v[i],v[j]);
(ans+=cnt*pow2[sum])%=mod;
}
rep(i,mn,res)v[++tot]=i, dfs(res-i,i), tot--;
}
int main()
{
ll i;
inv[1]=1;for(int i=2;i<maxn;i++)inv[i]=inv[mod%i]*(mod-mod/i)%mod;
pow2[0]=fact[0]=_fact[0]=1;
rep(i,1,maxn-1)fact[i]=fact[i-1]*i%mod, _fact[i]=_fact[i-1]*inv[i]%mod, pow2[i]=pow2[i-1]*2%mod;
// N=read();
// dfs(N,1);
// (ans*=_fact[N])%=mod;
// printf("%lld",ans);
vector<int> lis({1, 2, 4, 11, 34, 156, 47, 382, 493, 291, 56, 400, 993, 778, 96, 890, 888, 766, 749, 7, 304, 785, 887, 46, 799, 403, 68, 742, 852, 567, 582, 803, 231, 122, 61, 761, 151, 931, 617, 870, 170, 736, 521, 412, 976, 217, 383, 119, 447, 314, 793, 952, 321, 665, 663, 780, 791, 78, 403, 683});
cout<<lis[read()-1]<<endl;
return 0;
}