Luogu P4708 painting (Burnside lemma, the combination count)

Topic Link

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

answer

It looks Luogu P4706-4709 is Sdchr gods out of the game, a water problem and three very interesting question finally had a full memorial QAQ (However, after three all looked explanations)
and why this problem AC code is almost full He is playing table. .

Pre Title: BZOJ1488 seeking \ (n-\) th number of reference points None undirected graph. (Welcome https://www.cnblogs.com/suncongbo/p/11295453.html )
did not make a recommendation to do about that problem.

This question is still enumerator split, then the question now is how many points a given length of some degree of rotation required there are an even number of chart meet after the rotation effect remains the same.
First a property is the same for all points in the same degree rotation. (Obviously)
considering the rotation of the internal side, assuming that the rotation of length \ (L = 2S +. 1 \) , then there is \ (S \) different side groups, such that each side will set the degree of rotation of all points \ (2 + \) ; if the length of the rotation \ (2S \) , there \ (S \) different side group, wherein \ ((s-1) \ ) species (except diagonal) such that All points degrees \ (+ 2 \) , \ (1 \) kind of makes all the points degrees \ (+ 1 \) . degree \ (+ 2 \) does not change the parity obviously can not be considered a direct answer multiplied by \ ( 2 \) .
consider the edge between the rotation, the rotation is assumed that two lengths are \ (a, b \) there \ (\ gcd (a, b ) \) species group side, the inner side of each group comprising \ ( \ text {lcm} (a, b) \) edges, give \ (a \) point in degrees \ (+ \ frac {\ text {lcm} (a, b)} {a} \), To \ (B \) point in degrees \ (+ \ FRAC {\ text {LCM (A, B)}} {B} \) . If both an even number, the answer is multiplied by \ (2 ^ {\ GCD (a, B)} \) . If both of exactly one is odd, then the equivalent of \ (\ gcd (a, b ) \) chance to change the rotation odd parity. If both are odd, then the equivalent of \ (\ gcd (a, b ) \) chance to rotate while changing the parity of the two.

So the question into: there is a new plan (new Ituri point represents a rotation), initial point right are \ (0 \) , have for each point \ (c_i \) chances to change the parity of each while there \ (d_i \) chance while changing the parity of the two end points. How many kinds of programs required so that the final weight of all point to point \ (0 \) .
This conclusion is, for each change the total number of points is an even weight programs exist \ (2 ^ {\ sum d_i -cnt +1} \) species side operation scheme ( \ (CNT \) is the number of dots) corresponding thereto.
Emotional understanding, the right to change the point if it is clearly not an odd number, an even number, then you can build a DFS tree, after the non-operating side of the tree to any side of the tree always follow a bottom-up operation is completed operation.
Note that the official explanations written is wrong! Official explanations written directly \ (2 ^ {\ sum d_i } \) fucked me one night ......
the answer is \ (2 ^ {\ sum c_i -1} \ times 2 ^ {\ sum d_i-cnt + 1} \ ) .
problem is solved.

The time complexity with BZOJ 1488.

Code

#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;
}

Guess you like

Origin www.cnblogs.com/suncongbo/p/11297301.html