Luogu P4708絵(バーンサイドの補題、組み合わせ数)

トピックリンク

https://www.luogu.org/problem/P4708

問題の解決策

これは、(3すべての説明を見た後、しかし)Luogu P4706-4709ゲーム、水の問題と3つの非常に興味深い質問のうちSdchr神々が最終的に完全な記念QAQを持っているに見える
、なぜこの問題ACコードがほぼいっぱいです彼はテーブルを再生しています。

事前タイトル:BZOJ1488が求めて\(N- \)基準点なし無向グラフの目数。(ようこそhttps://www.cnblogs.com/suncongbo/p/11295453.html
その問題をどうする勧告をしませんでした。

この質問は、今の質問は、回転のある程度の所定の長さは、回転効果は同じまま後、チャートを満たすのにも多数ある必要どのように多くの点で、まだ列挙分割です。
最初のプロパティは、同じ程度の回転中のすべての点で同じです。(明らかに)
長の回転と仮定すると、内側の回転を考慮し\(L = 2S + 1 \)は、そこである\(S \)各側はすべての点の回転の程度が設定されるように、異なる側基、\(2 + \) ;回転の長さであれば\(2S \)そこ\(S \)の異なる側基であり、ここで\((S-1)\ ) (対角を除く)種ようすべてのポイントの度\(+ 2 \) \(1 \)は、一種のすべてのポイントの度になります\(+ 1 \) \(+ 2 \)を乗じた直接の回答と考えることができない、明らかにパリティを変更しません\( 2 \)
回転は2つの長さであることが想定され、回転の間のエッジを考える\(B \)(\ \ GCD(B )\) 種群側であって、各群の内側\を( \テキスト{LCM}( B)\) エッジを与える\(\)度にポイント\(+ \ FRAC {\テキスト {LCM}(B)}、{A} \)\(B \)度にポイント\(+ \ FRAC {\テキスト{LCM(A、B)}} {B} \) 偶数の両方が、答えが乗算された場合\(2 ^ {\ GCD(B)} \) 正確に一つの両方が奇数の場合、の次に等価\(\ GCD(B )\) 回転奇数パリティを変えるチャンス。両方が奇数であれば、その後の同等の\(\ GCD(A、B )\) 2のパリティを変えながら回転させるチャンス。

そこで問題に:新しい計画(新イトゥリポイントが回転を表し)、初期点の右されているがあります\(0 \) 各点を持っている\(C_I \)それぞれのパリティを変更するチャンスそこにしばらく\(D_I \)二つの端点のパリティを変えながらチャンス。何すべての点の最終重量を指すようになるように必要なプログラムの種類\(0 \)
この結論は、各変更のポイントの合計数はプログラムが存在しても重量である\(2 ^ {\和D_I -cnt +1} \)種側操作方式は、(\(CNT \)これに対応するドット数)です。
感情的な理解、それは明らかに奇数、偶数でない場合は、ツリーのいずれかの側に木の非操作側が常にボトムアップ動作が完了した操作を実行した後、あなたは、DFSツリーを構築することができ、ポイントを変更する権利。
書かれた公式の説明が間違っていることに注意してください!直接書き込ま公式な説明\(2 ^ {\和D_Iは } \) 一晩私をめちゃくちゃ......
答えは(2 ^ {\和C_I \ \ -1}回\ 2 ^ {\和D_I-CNT + 1}
問題が解決されます。

BZOJ 1488との時間複雑。

コード

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cassert>
#include<iostream>
#define llong long long
using namespace std;

inline int read()
{
    int x=0; bool f=1; char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
    for(; isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+(c^'0');
    if(f) return x;
    return -x;
}

const int N = 50;
const int P = 998244353;
llong fact[N*N*N+3],finv[N*N*N+3],inv[N*N*N+3],pw2[N*N*N+3];
int gcd[N+3][N+3];

int GCD(int x,int y) {return y==0 ? x : GCD(y,x%y);}

llong quickpow(llong x,llong y)
{
    llong cur = x,ret = 1ll;
    for(int i=0; y; i++)
    {
        if(y&(1ll<<i)) {y-=(1ll<<i); ret = ret*cur%P;}
        cur = cur*cur%P;
    }
    return ret;
}

void initmath(int n)
{
    fact[0] = 1ll; for(int i=1; i<=n; i++) fact[i] = fact[i-1]*i%P;
    finv[n] = quickpow(fact[n],P-2); for(int i=n-1; i>=0; i--) finv[i] = finv[i+1]*(i+1)%P;
    for(int i=1; i<=n; i++) inv[i] = finv[i]*fact[i-1]%P;
    pw2[0] = 1ll; for(int i=1; i<=n; i++) pw2[i] = pw2[i-1]*2ll%P;
}

int a[N+3],num[N+3];
int uf[N+3];
int c[N+3];
int n,cnt; llong ans;

int findfa(int u)
{
    int i = u;
    while(u!=uf[u]) {u = uf[u];}
    while(u!=uf[i])
    {
        int j = uf[i]; uf[i] = u; i = j;
    }
    return u;
}

void unionfa(int u,int v)
{
    int x = findfa(u),y = findfa(v);
    if(x!=y) {uf[x] = y;}
}

llong calc()
{
    for(int i=1; i<=cnt; i++) uf[i] = i,c[i] = 0;
    llong ret = fact[n];
    for(int i=1; i<=cnt; i++) {ret = ret*inv[a[i]]%P;}
    for(int i=1; i<=n; i++) {ret = ret*finv[num[i]]%P;}
    llong retp = 0ll;
    for(int i=1; i<=cnt; i++)
    {
        for(int j=i+1; j<=cnt; j++)
        {
            int g = gcd[a[i]][a[j]],lcm = a[i]*a[j]/g;
            int ci = lcm/a[i],cj = lcm/a[j];
            if((ci&1)==(cj&1))
            {
                retp += g;
                if(ci&1) {unionfa(i,j);}
            }
        }
    }
    for(int i=1; i<=cnt; i++)
    {
        for(int j=i+1; j<=cnt; j++)
        {
            int g = gcd[a[i]][a[j]],lcm = a[i]*a[j]/g;
            int ci = lcm/a[i],cj = lcm/a[j];
            int x = findfa(i),y = findfa(j);
            if((ci&1)!=(cj&1))
            {
                if(ci&1) {c[x]+=g;}
                else if(cj&1) {c[y]+=g;}
            }
        }
    }
    for(int i=1; i<=cnt; i++)
    {
        int x = findfa(i);
        retp += ((a[i]-1)>>1);
        if(!(a[i]&1)) {c[x]++;}
    }
    retp -= cnt;
    for(int i=1; i<=cnt; i++) {if(uf[i]==i) retp++;}
    for(int i=1; i<=cnt; i++)
    {
        if(uf[i]==i && c[i]>0)
        {
            retp += c[i]-1;
        }
    }
    ret = ret*pw2[retp]%P;
    return ret;
}

void dfs(int sum)
{
    if(sum==0)
    {
        ans = (ans+calc())%P;
    }
    for(int i=a[cnt]; i<=sum; i++)
    {
        cnt++; a[cnt] = i; num[i]++;
        dfs(sum-i);
        num[i]--; a[cnt] = 0; cnt--;
    }
}

int main()
{
    initmath(N*N*N);
    for(int i=1; i<=N; i++) for(int j=1; j<=N; j++) gcd[i][j] = GCD(i,j);
    scanf("%d",&n);
    a[0] = 1; dfs(n);
    ans = ans*finv[n]%P;
    printf("%lld\n",ans);
    return 0;
}

おすすめ

転載: www.cnblogs.com/suncongbo/p/11297301.html