ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[SDOI2013]方程

2022-07-13 12:32:05  阅读:157  来源: 互联网

标签:方程 return int ll SDOI2013 ex ans mul


description

给定方程\(x_1+x_2+...+x_n=m\)和\(n_1\),\(n_2\)
对于\(i\in [1,n_1]\): \(x_i\le a_i\)
对于\(i\in [n_1+1,n_1+n_2]\):\(x_i\ge a_i\)
问正整数结的个数且\(p<=437367875\)(不一定是质数), \(n,m<=10^9\), \(n_1,n_2<=8\)

solution

首先这种解的个数常见插板法套路了。
对于\(n_2\)那一类:给\(m\)减去\(a_i-1\),即求正整数解的方案数了。
而\(n_1\)那一类,\(n_1\)又那么小,求的是\(n_1\)个条件的交集,直接容斥。
发现逆向才可求,即求满足一些\(x_i\ge a_i+1\)的方案数,回到第二类问题。
容斥枚举集合乘\((-1)^{|S|}\)应该都会吧。
毒瘤的是模数不一定是质数,所以要用ex_lucus。(我当然直接贺过来)
ex_lucus还要预处理阶乘,不然会T。

code

点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
const int M=5e6+5;
ll r[M],md[N],a[N],jc[M];
ll ksm(ll t,ll b,ll mod) {
	ll mul=1;
	for(ll i=b;i;i>>=1) {
		if(i&1) mul=mul*t%mod; t=t*t%mod;
	}
	return mul;
}
ll ex_gcd(ll a,ll b,ll &x,ll &y) {
	if(b==0) {x=1; y=0; return a;}
	ll d=ex_gcd(b,a%b,x,y);
	ll xx=x; x=y; y=xx-a/b*y;
	return d;
}
ll inv(ll u,ll p) {
	ll v,k,d=ex_gcd(u,p,v,k);
	v%=(p/d);
	if(v<0) v+=(p/d);
	return v;
}
ll fac(ll n,ll pk,ll p) {
	if(n==0||n==1) return 1;
	return fac(n/p,pk,p)*ksm(jc[pk],n/pk,pk)%pk*jc[n%pk]%pk;
}
ll Cnt(ll n,ll p) {
	ll sum=0;
	for(ll i=n;i;i/=p) sum+=i/p;
	return sum;
}
ll C_modpk(ll n,ll m,ll p,ll pk)	{
	jc[0]=1;
	for(ll i=1;i<=pk;i++) 
		if(i%p) jc[i]=jc[i-1]*i%pk;
		else jc[i]=jc[i-1];
	return fac(n,pk,p)*inv(fac(m,pk,p),pk)%pk*inv(fac(n-m,pk,p),pk)%pk*ksm(p,(Cnt(n,p)-Cnt(m,p)-Cnt(n-m,p)),pk)%pk;
}
ll CRT(int tot) {
	ll mul=1,sum=0,x,y;
	for(int i=1;i<=tot;i++) mul*=md[i];
	for(int i=1;i<=tot;i++) {
		ll d=ex_gcd(mul/md[i],md[i],x,y);
		sum+=(mul/md[i])*x%mul*r[i]%mul%mul,sum=(sum%mul+mul)%mul;
	}
	return sum;
}
ll ex_Lucas(ll n,ll m,ll P) {
    if(n<m) return 0;
	int tot=0;
	for(ll p=2;p*p<=P;p++) {
		ll pk=1;
		if(!(P%p)) {
			while(!(P%p)) {P/=p; pk*=p; }
			md[++tot]=pk; r[tot]=C_modpk(n,m,p,pk);
		}
	} 
	if(P>1) {
		md[++tot]=P; r[tot]=C_modpk(n,m,P,P);
	}
	ll ans=CRT(tot);
	return ans;
}
int main() {
	int T;
	ll sum=0,p;
	scanf("%d%lld",&T,&p);
	while(T--) {
		ll n,n1,n2,m,ans;
		scanf("%lld%lld%lld%lld",&n,&n1,&n2,&m);
		for(int i=0;i<n1+n2;i++) {
			scanf("%lld",&a[i]);
			if(i>=n1) m-=a[i]-1;
		}
		ans=ex_Lucas(m-1,n-1,p)%p;
		for(int s=1;s<(1<<n1);s++) {
			ll cnt=0,tmp=m;
			for(int i=0;i<n1;i++) {
				if(s&(1<<i)) {
					cnt++,tmp-=a[i];
				}
			} 
			if(cnt&1) ans-=ex_Lucas(tmp-1,n-1,p);
			else ans+=ex_Lucas(tmp-1,n-1,p);
			ans=(ans%p+p)%p;
		}
		printf("%lld\n",(ans%p+p)%p);
	}
	return 0;
}

标签:方程,return,int,ll,SDOI2013,ex,ans,mul
来源: https://www.cnblogs.com/bestime/p/16473427.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有