简单题(数论)

同一道题:小狗狗也AK了!

题面

两个长度为 K K K 的正整数数列 a a a b b b,满足 ∑ i = 1 K a i = N   ,   ∑ i = 1 K b i = M \sum_{i=1}^Ka_i=N~,~\sum_{i=1}^Kb_i=M i=1Kai=N , i=1Kbi=M,对于这两个数列,定义权值为 P = ∏ i = 1 K min ⁡ ( a i , b i ) P=\prod_{i=1}^K\min(a_i,b_i) P=i=1Kmin(ai,bi) 。求所有可能的数列的权值之和。答案对 998244353 998244353 998244353 取模。

T T T 组数据,每组数据给出 N , M , K N,M,K N,M,K

T ≤ 100 , 1 ≤ N , M , K ≤ 5 × 1 0 5 , K ≤ min ⁡ ( N , M ) T\leq 100,1\leq N,M,K\leq5\times10^5,K\leq\min(N,M) T100,1N,M,K5×105,Kmin(N,M)

题解

做一个转换:『权值』即为长度为 K K K 的正整数数列 c c c 的数量,满足 ∀ i ∈ [ 1 , K ]   ,   c i ≤ a i , c i ≤ b i \forall i\in[1,K]~,~c_i\leq a_i,c_i\leq b_i i[1,K] , ciai,cibi

我们反向求,先求 c c c 的数量,再求与之对应的 ( a , b ) (a,b) (a,b) 方案数。

假设我们确定了 c c c,我们可以令 a i = a i − c i   ,   b i = b i − c i a_i=a_i-c_i~,~b_i=b_i-c_i ai=aici , bi=bici ,然后 a , b a,b a,b 就成了长度为 K、总和分别为 N − ∑ c i N-\sum c_i Nci M − ∑ c i M-\sum c_i Mci 的自然数数列

因此,枚举 x = ∑ c i x=\sum c_i x=ci ,对应的 c c c 的数量为 C ( x − 1 , K − 1 ) C(x-1,K-1) C(x1,K1) a a a 的数量为 C ( M − x − 1 + K , K − 1 ) C(M-x-1+K,K-1) C(Mx1+K,K1) b b b 的数量为 C ( M − x − 1 + K , K − 1 ) C(M-x-1+K,K-1) C(Mx1+K,K1)

于是,答案为
∑ x = K min ⁡ ( N , M ) C ( x − 1 , K − 1 ) ⋅ C ( M − x − 1 + K , K − 1 ) ⋅ C ( M − x − 1 + K , K − 1 ) \sum_{x=K}^{\min(N,M)} C(x-1,K-1)\cdot C(M-x-1+K,K-1)\cdot C(M-x-1+K,K-1) x=Kmin(N,M)C(x1,K1)C(Mx1+K,K1)C(Mx1+K,K1)

CODE

很快啊

#include<map>
#include<set>
#include<stack>
#include<queue>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 500005
#define LL long long
#define DB double
#define ENDL putchar('\n')
#define lowbit(x) (-(x):(x))
#define SI(x) set<x>::iterator
#define FI first
#define SE second
LL read() {
	LL f=1,x=0;char s = getchar();
	while(s < '0' || s > '9') {if(s=='-')f = -f;s = getchar();}
	while(s >= '0' && s <= '9') {x=x*10+(s-'0');s = getchar();}
	return f * x;
}
void putpos(LL x) {
	if(!x) return ;
	putpos(x/10); putchar('0'+(x%10));
}
void putnum(LL x) {
	if(!x) {putchar('0');return ;}
	if(x < 0) putchar('-'),x = -x;
	putpos(x);
}
void AIput(LL x,char c) {putnum(x);putchar(c);}

const int MOD = 998244353;
int n,m,s,o,k;
int fac[MAXN<<1],inv[MAXN<<1],invf[MAXN<<1];
int C(int n,int m) {
	if(m < 0 || m > n) return 0;
	return fac[n] *1ll* invf[n-m] % MOD * invf[m] % MOD;
}
int main() {
	freopen("easy.in","r",stdin);
	freopen("easy.out","w",stdout);
	fac[0]=fac[1]=inv[0]=inv[1]=invf[0]=invf[1]=1;
	for(int i = 2;i <= MAXN*2-5;i ++) {
		fac[i] = fac[i-1] *1ll* i % MOD;
		inv[i] = (MOD - inv[MOD%i]) *1ll* (MOD/i) % MOD;
		invf[i] = invf[i-1] *1ll* inv[i] % MOD;
	}
	
	int T = read();
	while(T --) {
		n = read();m = read();k = read();
		if(n > m) swap(n,m);
		int ans = 0;
		for(int i = k;i <= n;i ++) {
			int bs = C(i-1,k-1);
			int ct = C(n-i-1+k,k-1) *1ll* C(m-i-1+k,k-1) % MOD;
			(ans += bs*1ll*ct % MOD) %= MOD;
		}
		AIput(ans,'\n');
	}
	return 0;
}
由于目没有具体说明是哪个作业的练习,因此无法提供准确的答案。数论是关于整数性质与结构的研究,涉及到整数的基本性质,因此答案需要根据具体的目来给出。以下是一些数论导引练习的一般解答方法: 1. 证明素数无穷多个: 答案:假设素数只有有限个,标记为p1, p2, ..., pn。然后构造一个新的数q,q = p1p2...pn +1。由于1不是素数,所以q一定是一个素数。这样我们得到了比已知的所有素数都大的素数q,与假设矛盾,因此素数无穷多个。 2.证明方程x^2 + y^2 = z^2 在正整数解中有无穷多个: 答案:首先,我们可以构造一个简单的解(x,y,z) = (3,4,5)。然后考虑将这个解乘以一个正整数k得到新的解(x',y',z')=(3k,4k,5k)。由于k是任意的正整数,所以可以构造出无穷多个解。因此,方程在正整数解中有无穷多个。 3.证明质数的乘积加一不是素数: 答案:假设质数的乘积加一是一个素数,标记为p。然后考虑将p减去1,得到p-1。根据欧拉定理,如果p是一个质数,那么p-1一定能被p的某一个质因数整除。但由于p-1是p的倍数,所以p也能整除p-1,这与p是一个素数矛盾。因此,质数的乘积加一不是素数。 总之,数论是一个广泛而深入的领域,需要具体问题具体分析,根据目中给出的具体条件进行推导和证明。以上是一些常见的解答方法,但无法确定具体的目,所以答案可能不是完整的或不适用于特定的练习
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值