cf 997c Sky Full of Stars(组合数+容斥原理)

Sky Full of Stars

On one of the planets of Solar system, in Atmosphere University, many students are fans of bingo game.

It is well known that one month on this planet consists of n2
days, so calendars, represented as square matrix n by n

are extremely popular.

Weather conditions are even more unusual. Due to the unique composition of the atmosphere, when interacting with sunlight, every day sky takes one of three colors: blue, green or red.

To play the bingo, you need to observe the sky for one month — after each day, its cell is painted with the color of the sky in that day, that is, blue, green or red.

At the end of the month, students examine the calendar. If at least one row or column contains only cells of one color, that month is called lucky.

Let’s call two colorings of calendar different, if at least one cell has different colors in them. It is easy to see that there are 3n⋅n
different colorings. How much of them are lucky? Since this number can be quite large, print it modulo 998244353

.

Input

The first and only line of input contains a single integer n

(1≤n≤1000000

) — the number of rows and columns in the calendar.

Output

Print one number — number of lucky colorings of the calendar modulo 998244353

Examples
Input

1

Output

3

Input

2

Output

63

Input

3

Output

9933

Note

In the first sample any coloring is lucky, since the only column contains cells of only one color.

In the second sample, there are a lot of lucky colorings, in particular, the following colorings are lucky:

这里写图片描述
While these colorings are not lucky:
这里写图片描述

题意:

用三种颜色对 n × n 的格子染色,问至少有一行或者一列只有一种颜色的方案数有多少( n 10 6

分析:

定义 A i 为第i行只有一种颜色的集合,定义 B i 为第i列只有一种颜色的集合

那么问题转化成了求

| A 1 A 2 A n B 1 B 2 B n |

容易想到可以使用容斥原理来求解这个问题

那么现在的目标就是推导公式了

由于对称性,计算A中一些集合和B中一些集合的交集大小不需要知道两个集合具体包含哪些元素,只需要知道各种颜色的个数

我们假设n行n列中选择其中i行j列来染成相同的颜色,那么得到公式

a n s = i , j = 0 , i + j > 0 n C n i C n j ( 1 ) i + j + 1 f ( i , j )

解释一下上面的式子, C n i C n j 即代表在n行n列中任意选取i行j列的方案数,既然行列的选择方式已经在 C n i C n j 中体现了,那么 f ( i , j ) 只需要表示前i行前j列只有一个颜色的方案数即可。

对于 f ( i , j ) 取值需要分两种情况

当其中一个参数为0的时候:
如图:
这里写图片描述
即保证了行或者列涂上一种颜色是 3 k

剩下的格子共有 n ( n k ) 个,这些格子随便涂因此

f ( 0 , k ) = 3 k 3 n ( k k )

因为i为0和j为0是相同的,所以当有一个参数为0的时候的总方案数是:

2 3 k 3 n ( n k )

当没有一个参数为0的时候,即一般情况:
如图:

此时是这种情况,那么选中的部分只有3种选择,因为选中部分颜色只能全一样

剩下部分的格子有 ( n i ) ( n j )

那么

f ( i , j ) = 3 3 ( n i ) ( n j )


因此我们可以分开求两种情况,最后再加起来

对于有一个参数数为0的情况,直接1-n枚举即可,套用公式

a n s = i , j = 0 , i + j > 0 n C n i C n j ( 1 ) i + j + 1 f ( i , j )

= i = 1 n 2 × C n i ( 1 ) i + 1 3 i 3 n ( n i )

注意乘二是因为可以行为0,可以列为0,共两种情况,每种都是一样的

对于参数都不为0的情况即一般情况
我们需要求

a n s = i , j = 0 , i + j > 0 n C n i C n j ( 1 ) i + j + 1 f ( i , j )

a n s = i , j = 0 , i + j > 0 n C n i C n j ( 1 ) i + j + 1 3 3 ( n i ) ( n j )

a n s = i = 0 n j = 0 n C n i C n j ( 1 ) i + j + 1 3 3 ( n i ) ( n j )

如果直接二次循环求解必然会超时

因此我们下面对式子进行化简

a n s = i = 0 n j = 0 n C n i C n j ( 1 ) i + j + 1 3 3 ( n i ) ( n j )

改变枚举变量,用 n i i n j j 得:
a n s = 3 i = 0 n 1 j = 0 n 1 C n n i C n n j ( 1 ) n i + n j + 1 3 i j

= 3 i = 0 n 1 j = 0 n 1 C n n i C n n j ( 1 ) 2 n ( i + j ) + 1 3 i j

因为 C n n i = C n i , ( 1 ) 2 n = 1 , ( 1 ) i = ( 1 ) i

= 3 i = 0 n 1 j = 0 n 1 C n i C n j ( 1 ) i + j + 1 3 i j

= 3 i = 0 n 1 C n i ( 1 ) i + 1 j = 0 n 1 C n j ( 1 ) j ( 3 i ) j

= 3 i = 0 n 1 C n i ( 1 ) i + 1 j = 0 n 1 C n j ( 3 i ) j

根据二项式定理 ( a + b ) n = i = 0 n C n i a i b n i

所以原式

= 3 i = 0 n 1 C n i ( 1 ) i + 1 j = 0 n 1 C n j ( 3 i ) j ( 1 ) n j

= 3 i = 0 n 1 C n i ( 1 ) i + 1 [ ( 1 + ( 3 i ) ) n ( 3 i ) ] n

为什么最后又减了个 ( 3 i ) n 呢,因为原式中是从1加到n-1,所以化成二项式后就多了一项,我们需要减去

那么对于这种情况我们也化简为了一重求和,那么直接一重循环套公式就能搞定。

注意预处理处组合数

code:

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6+7;
const int mod = 998244353;
ll n,c[maxn],ans;//c[i]表示C(n,i)

ll q_pow(ll a,ll b){
        ll ans = 1;
        while(b){
                if(b & 1)
                        ans = ans * a % mod;
                a = a * a % mod;
                b >>= 1;
        }
        return ans;
}
int main(){
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    scanf("%lld",&n);
        c[0] = 1;
        for(int i = 1; i <= n; i++){
                c[i] = c[i-1] * (n - i + 1) % mod * q_pow(i,mod-2) % mod;
        }
        ans = 0;
        for(int i = 0; i < n; i++){//一般情况
                ll s = q_pow(3,i);
                ll t1 = q_pow(1-s,n),t2 = q_pow(-s,n);
                ll d = (c[i] * (t1 - t2) % mod + mod) % mod;
                if(i & 1) ans += d;
                else ans -= d;
                ans = (ans % mod + mod) % mod;
        }
        ans = ans * 3 % mod;
        for(int i = 1; i <= n; i++){//有一个参数为0的情况
                ll d = q_pow(3,i) * q_pow(3,n*(n-i)) % mod;
                d = c[i] * d % mod;
                if(i & 1) ans += 2 * d;
                else ans -= 2 * d;
                ans = (ans % mod + mod) % mod;
        }
        printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/codeswarrior/article/details/81906327
sky