包除原理 - ポイント糖(SOJ 747)

免責事項:この記事はブロガーオリジナル記事です、続くBY-SAのCC 4.0を著作権契約、複製、元のソースのリンクと、この文を添付してください。
このリンク: https://blog.csdn.net/weixin_42557561/article/details/100046173

シュガーポイント

タイトル説明

N(同)キャンディ、M(別の)子供があります。M及びNを満たす:1≤M≤N≤100000(105)。
要件:
1.それぞれの子には少なくとも一つのお菓子を持っています。
2.正の整数X(X> = 2)キャンディの数はそれぞれの子は、複数のXであるように、存在しません
3.残りのお菓子はできません。
パーティション化された全糖方法。1000000007応答モード(109 + 7)

入力形式

T <= 100000:行動データセットの最初の数。
次のN行、本明細書に示すように、各列2つの正の整数N、M。

出力フォーマット

出力Tライン、答えのための各整数、。
ノートテイク!


分析

難易度は、友人:)多くの問題ではない
通常の抗難しいそれは
、我々はそれぞれの子があるお菓子の数の倍数をカウントXの
明確なXは、Nの要因であることを
質問が品質係数のN分解になるように
、封入排除何
語のプログラム番号は、B、空でないケースのセットにアイテムの異なるセットと同一であります
A n個 S = C A - 1 B - 1 年間= C_ { - 1} ^ {B-1}


コード

#include<bits/stdc++.h>
#define int long long
#define re register
#define in read()
using namespace std;
inline int read(){
	char ch;int f=1,res=0;
	while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
	while(ch>='0'&&ch<='9'){
		res=(res<<1)+(res<<3)+(ch^48);
		ch=getchar();
	}
	return f==1?res:-res;
}
const int N=1e5;
const int P=1e9+7;
typedef long long ll;
int T,n,m;
int fac[N+10],ifac[N+10];
inline ll ksm(ll x,ll b){
	ll res=1;
	while(b){
		if(b&1) res=res*x%P;
		x=x*x%P;
		b>>=1;
	}
	return res;
}
int mark[N+10],pri[N+10],tot=0;
void init(){
	for(re int i=2;i<=N;++i){
		if(!mark[i]) pri[++tot]=i;
		for(re int j=1;j<=tot&&i*pri[j]<=N;++j){
			mark[i*pri[j]]=1;
			if(i%pri[j]==0) break;
		}
	}
	fac[0]=1;
	for(re int i=1;i<=N;++i) fac[i]=fac[i-1]*i%P;
	ifac[N]=ksm(fac[N],P-2);
	for(re int i=N-1;i>=0;--i) ifac[i]=ifac[i+1]*(i+1)%P;
}
int cnt=0,a[N];
void divide(int x){
	for(re int i=1;pri[i]*pri[i]<=x&&i<=tot;++i)
		if(x%pri[i]==0){
			a[++cnt]=pri[i];
			while(x%pri[i]==0) x/=pri[i];
		}
	if(x>1) a[++cnt]=x;
}
ll C(ll x,ll y){
	if(y>x) return 0;
	return fac[x]*ifac[y]%P*ifac[x-y]%P;
}
bool cmp(const int a,const int b){return a>b;}
ll ans;
void dfs(int pos,int sum,int t){
	if(pos>cnt){
		int x=n/sum;
		if(t) ans=(ans-C(x-1,m-1))%P;
		else ans=(ans+C(x-1,m-1))%P;
		return;
	}
	dfs(pos+1,sum*a[pos],t^1);
	dfs(pos+1,sum,t);
}
void work(){
	cnt=0;
	divide(n);
	ans=0;
	sort(a+1,a+cnt+1,cmp);
	dfs(1,1,0);
	cout<<((ans%P+P)%P)<<'\n';
}
signed main(){
	T=in;
	init();
	while(T--){
		n=in;m=in;
		if(n==m) puts("1");
		else work();		
	}
	return 0;
}

おすすめ

転載: blog.csdn.net/weixin_42557561/article/details/100046173