列表

详情


NC20190. [JSOI2011]同分异构体计数

描述

Antonio 最近对有机化学比较感兴趣,他想请你帮助他快速计算出某种烃类的同分异 构体的数目。  
为了表述方便,我们作出如下定义:    
环烷烃: 具有n 个碳原子的环烷烃可以表示成一张具有n 个顶点n 条边的无向连通 简单图(基环+外向树)。每个顶点的度数不超过 4。    
M-环烷烃:至多有m 个顶点在环上的环烷烃。(注意环上至少有 3 个顶点,因为 任意两个顶点之间至多只能有1 条边)。   
同构:假设结构A和结构B均具有n 个碳原子,A和B 同构当且仅当能够对A和 B 中的每个碳原子都按照 1~n 编号,使得对于编号为 v1 和 v2 的两个碳原子,他们在A中存在边相连当且仅当他们在 B中存在边相连。(换言之,A和 B对应的图 同构)。  
现在,给出n, m,Antonio 希望你帮助他统计有多少种互不同构的含有n个碳原子的 m-环烷烃。由于这个数量可能很大,你只需要输出它对p 的余数。(p是一个素数)。  
在本题中,我们不考虑某结构在化学上是否能够稳定存在,也不考虑其他的异构方式。

输入描述

输入文件只有一行,用空格隔开的三个整数n, m, p 。
保证有m ≤ n,p为素数。

输出描述

输出文件有且仅有一行,表示具有n 个碳原子的互不同构的m-环烷烃的数量,对 p的余数。

示例1

输入:

10 10 66103

输出:

476

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 832ms, 内存消耗: 816K, 提交时间: 2020-02-19 09:42:26

#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 1010
#define maxm 55
#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;
}
ll f[maxn], f2[maxn], f3[maxn], g[maxn], N, M, inv[maxn], mod, dp[maxm][maxn];
ll fastpow(ll a, ll b, ll c)
{
    ll t(a%c), ans(1ll);
    for(;b;b>>=1,t=t*t%c)if(b&1)ans=ans*t%c;
    return ans;
}
int main()
{
    ll i, j, k, n=read(), m=read();
    mod=read();
    inv[1]=1;for(int i=2;i<maxn;i++)inv[i]=inv[mod%i]*(mod-mod/i)%mod;
    f[0]=f2[0]=f3[0]=1;
    rep(i,1,n)
    {
        f[i]=f3[i-1];
        for(j=0;2*j<=i-1;j++)(f[i]+=3*f[j]*f[i-1-2*j])%=mod;
        if((i-1)%3==0)(f[i]+=2*f[(i-1)/3])%=mod;
        (f[i]*=inv[6])%=mod;

        g[i]=f2[i-1];
        if((i-1)%2==0)(g[i]+=f[i-1>>1])%=mod;
        (g[i]*=inv[2])%=mod;

        for(j=0;j<=i;j++)(f2[i]+=f[j]*f[i-j])%=mod;
        for(j=0;j<=i;j++)(f3[i]+=f[j]*f2[i-j])%=mod;

        // printf("f[%lld]=%lld g=%lld\n",i,f[i],g[i]);
    }
    dp[0][0]=1;
    rep(i,1,m)rep(j,1,n)rep(k,1,j)(dp[i][j]+=dp[i-1][j-k]*g[k])%=mod;
    ll ans=0, tot=0;
    rep(i,3,m)
    {
        // printf("i=%lld\n",i);
        ll tmp=0;
        rep(j,0,i-1)
        {
            ll cnt=__gcd(j,i), sz=i/cnt;
            if(n%sz==0)tmp += dp[cnt][n/sz];
            tmp %= mod;
            // printf("        j=%lld tmp=%lld cnt=%lld sz=%lld dp=%lld\n",j,tmp,cnt,sz,dp[cnt][n/sz]);
        }
        // printf("    tmp=%lld tot=%lld\n",tmp,tot);
        // de(tmp), de(tot);
        if(i%2==0)
        {
            for(j=1;j<=n;j++)for(k=1;j+k<=n;k++)
            {
                if((n-j-k)%2!=0)continue;
                tmp += (dp[1][j]*dp[1][k]%mod*dp[(i-2)/2][(n-j-k)/2]%mod*(i>>1))%mod;
                tmp %= mod;
            }
            if(n%2==0)
            {
                tmp += dp[i>>1][n/2]*(i>>1);
                tmp %= mod;
            }
        }
        if(i%2==1)
        {
            for(j=1;j<=n;j++)
            {
                if((n-j)%2==0)tmp += (dp[1][j]*dp[(i-1)/2][n-j>>1]%mod*i)%mod;
                // printf("        j=%lld tmp=%lld\n",j, tmp);
                tmp %= mod;
            }
        }
        // de(tmp), de(tot);
        tmp = tmp*fastpow(2*i,mod-2,mod) %mod;
        ( ans += tmp ) %=mod;
        // printf("    ans=%lld add=%lld\n",ans,tmp);
    }
    printf("%lld\n",ans);
    return 0;
}

C++11(clang++ 3.9) 解法, 执行用时: 627ms, 内存消耗: 872K, 提交时间: 2020-03-08 23:16:57

#include<cstdio>
typedef unsigned long long u64;
typedef unsigned int u32;
int n,m;
u32 P;
int gcd(int a,int b)
{
	for(int c;b;c=a,a=b,b=c%b);
	return a;
 } 
 int phi(int n)
 {
 	int v=n;
 	for(int i=2;i*i<=n;++i)
 	if(n%i==0)
 	{
 		do n/=i;while(n%i==0);
 		v=v/i*(i-1);
	 }
	 if(n>1) v=v/n*(n-1);
	 return v;
 }
 inline u32 fix(int a)
 {
 	return a+(a>>31&P);
 }
 struct num
 {
 	u32 x;
 	num(u32 a=0):x(a){}
	num operator+(num w)
	{
		return fix(x+w.x-P);
	}
	num operator*(num w)
	{
		return u64(x)*w.x%P;
	}
	void operator+=(num w)
	{
		x=fix(x+w.x-P);
	}
 };
 num s[5][1007],gs[11],iv[117],f0[57][1007],f1[57][1007],ans;
 void cal(int m,int n)
 {
 	int g=gcd(n,m);
 	num v=0;
 	for(int d=1;d<=g;++d)
 	if(g%d==0)
 	v+=f0[m/d][n/d]*phi(d);
 	v+=f1[m][n]*m;
 	ans+=v*iv[m*2];
 }
 int main()
 {
 	scanf("%d%d%u",&n,&m,&P);
 	if(m>n) m=n;
 	s[0][0]=iv[1]=1;
 	for(int i=2;i<=115;++i) iv[i]=iv[P%i]*(P-P/i);
 	for(int i=1;i<=n;++i)
 	{
 		f0[1][i]=f1[1][i]=s[0][i-1]+s[1][i-1]+s[2][i-1];
 		gs[1]=f0[1][i]+s[3][i-1];
 		for(int j=2;j<=3;++j) gs[j]=gs[j-1]*(gs[1]+(j-1))*iv[j];
 		for(int j=3;j;--j)
 		{
 			for(int k=n;k>=i;--k)
 			{
 				for(int t=1;t<=j;++t)
 				{
 					int w=k-t*i;
 					if(w>=0) s[j][k]+=gs[t]*s[j-t][w];
				 }
			 }
		 }
	 }
	 for(int i=2;i<=m;++i)
	 {
	 	for(int j=i;j<=n;++j)
	 	{
	 		for(int k=1;k<j;++k)
	 		f0[i][j]+=f0[i-1][j-k]*f0[1][k];
	 		if(i&1)
	 		{
	 			for(int k=2;k<j;k+=2)
	 			f1[i][j]+=f0[i>>1][k>>1]*f0[1][j-k];
			 }
			 else
			 {
			 	for(int k=1;k<j;++k) f1[i][j]+=f1[i-1][j-k]*f0[1][k];
			 	if(~j&1) f1[i][j]+=f0[i>>1][j>>1];
			 	f1[i][j]=f1[i][j]*iv[2];
			 }
		 }
	 }
	 for(int i=3;i<=m;++i) cal(i,n);
	 printf("%d\n",ans.x);
	 return 0;
 }

上一题