阶乘逆元+巧妙解法

B - RGB Coloring


Time limit時間制限 : 2sec / Memory limitメモリ制限 : 1024MB

配点 : 700

問題文

高橋君はタワーを 1 つ持っており、それは N 個のブロックが縦一列に重なって構成されています。 はじめすべてのブロックは無色ですが、高橋君はいくつかのブロックを赤色、緑色、青色のいずれかの色で塗ることで、 タワーを美しくしようとしています。そこで、高橋君は タワーの美しさ を以下のように定義することにしました。

  • 各ブロックの得点を、赤色に塗られていれば A 点、緑色に塗られていれば A+B 点、青色に塗られていれば B 点、無色ならば 0 点として、 N 個のブロックの得点の合計をタワーの美しさとする。

ただし、A,B はあらかじめ与えられる正整数の定数であり、各マスが 2 つ以上の色で同時に塗られることがないことにも注意してください。

高橋君はタワーの美しさがちょうど K になるようにブロックを塗ろうと考えています。 そのようにタワーを塗る方法は何通りあるでしょうか。 998244353 で割った余りを求めてください。 ただし、2 つのタワーを塗る方法が異なるとは、あるブロックが存在し、そのブロックに塗られている色が異なること、もしくは、そのブロックが一方では塗られているが、 他方では無色であることを指します。

制約

  • 1≦N≦3×105
  • 1≦A,B≦3×105
  • 0≦K≦18×1010
  • 入力される値は全て整数である

入力

入力は以下の形式で標準入力から与えられる。

N A B K

出力

タワーを塗る方法の個数を 998244353 で割った余りを出力せよ。


入力例 1

Copy
4 1 2 5

出力例 1

Copy
40

この場合、赤色 1 つにつき 1 点、緑色 1 つにつき 3 点、青色 1 つにつき 2 点なので、美しさが 5 になるのは、

  • 緑色 1 つ、青色 1
  • 赤色 1 つ、青色 2
  • 赤色 2 つ、緑色 1
  • 赤色 3 つ、青色 1

のいずれかの場合だけです。よって、求める答えは 40 になります。


入力例 2

Copy
2 5 6 0

出力例 2

Copy
1

美しさが 0 であるタワーは、すべてのブロックが無色であるものだけです。よって、答えは 1 になります。


入力例 3

Copy
90081 33447 90629 6391049189

出力例 3

Copy
577742975

Score : 700 points

Problem Statement

Takahashi has a tower which is divided into N layers. Initially, all the layers are uncolored. Takahashi is going to paint some of the layers in red, green or blue to make a beautiful tower. He defines the beauty of the tower as follows:

  • The beauty of the tower is the sum of the scores of the N layers, where the score of a layer is A if the layer is painted red, A+B if the layer is painted green, B if the layer is painted blue, and 0 if the layer is uncolored.

Here, A and B are positive integer constants given beforehand. Also note that a layer may not be painted in two or more colors.

Takahashi is planning to paint the tower so that the beauty of the tower becomes exactly K. How many such ways are there to paint the tower? Find the count modulo 998244353. Two ways to paint the tower are considered different when there exists a layer that is painted in different colors, or a layer that is painted in some color in one of the ways and not in the other.

Constraints

  • 1N3×105
  • 1A,B3×105
  • 0K18×1010
  • All values in the input are integers.

Input

Input is given from Standard Input in the following format:

N A B K

Output

Print the number of the ways to paint tiles, modulo 998244353.


Sample Input 1

Copy
4 1 2 5

Sample Output 1

Copy
40

In this case, a red layer worth 1 points, a green layer worth 3 points and the blue layer worth 2 points. The beauty of the tower is 5 when we have one of the following sets of painted layers:

  • 1 green, 1 blue
  • 1 red, 2 blues
  • 2 reds, 1 green
  • 3 reds, 1 blue

The total number of the ways to produce them is 40.


Sample Input 2

Copy
2 5 6 0

Sample Output 2

Copy
1

The beauty of the tower is 0 only when all the layers are uncolored. Thus, the answer is 1.


Sample Input 3

Copy
90081 33447 90629 6391049189

Sample Output 3

Copy
577742975

题意:输入n,a,b,k,分别代表有n个柱子,每个柱子能涂3种颜色,也可以不涂,每种颜色的价值分别为a,b,a+b,问有多少种图法能使最后所有柱子的和为k,每个柱子只能涂一种颜色

解法:阶乘逆元O(N)来求C,最后利用题目中告诉你的一根柱子不能涂两种及以上颜色,将一个柱子既涂a的颜色,又涂b的颜色,这样这根柱子就变成了a+b的颜色(仿佛是出题者对做题者智商的讽刺),只需要找出满足ax+by=k的x,y即可,最后
sum+=C(n,x)*C(n,y)                                                                                                                                                                                                
代码
#include
using namespace std;
#define N 300007
#define MAX 300000
#define mod 998244353
long long fac[N];
long long inv[N];
long long quick_power(long long p,long long t)//快速幂 
{
	long long sum=1;
	while(t)
	{
		if(t&1) sum=sum*p%mod;
		p=p*p%mod;
		t>>=1;
	}
	return sum;
}

void pre()//阶乘取模,阶乘逆元取模 
{
	fac[0]=1;
	for(long long i=1;i<=MAX;++i)
		fac[i]=(i*fac[i-1])%mod;
	inv[MAX]=quick_power(fac[MAX],mod-2);
	for(long long i=MAX-1;i>=0;--i)
		inv[i]=inv[i+1]*(i+1)%mod;
}

long long Cc(long long a,long long b)
{
	return fac[a]*inv[b]%mod*inv[a-b]%mod;
}

int main()
{
	pre();
	long long n,a,b,k;
	cin>>n>>a>>b>>k;
	long long sum=0; 
	for(long long i=0;i<=n&&i*a<=k;++i)
	{
		long long left=k-i*a;
		if(left%b==0&&(left/b)<=n)
		{
			long long j=left/b;
			sum=sum+Cc(n,i)*Cc(n,j)%mod; 
		}
	}
	cout<

你可能感兴趣的:(C++,习题,组合数学)