Acm学习日程—六月二十八

一、主要知识点

1.gcd(f(x),f(y))=f(gcd(x,y));

2.fibonacci 、阶乘、加法、乘法及逆元取模计算

3.输入输出(c++)加快速度方法

二、多校第六场 bookshelf

1.解题思路

g一定为n的因子,

eg:   x1+x2+....xk=n;    gcd(x1,x2,x3,...xk)=1;               

        方案数=因子为1的方案数( C(n/1+k-1,k-1))—后面的因子被1整除的方案数之和(容斥)   

        x1+x2+....xk=n/2;    gcd(x1,x2,x3,...xk)=2;(相当在1的基础上,将每个x*2,则最大公因数必为2)           

        方案数=因子为2的方案数( C(n/2+k-1,k-1))—后面的因子被2整除的方案数之和(容斥)

        ..............

        x1+x2+....xk=n/i;    gcd(x1,x2,x3,...xk)= i ;(相当在1的基础上,将每个x*i,则最大公因数必为i)           

        方案数=因子为2的方案数( C(n / i+k-1,k-1))—后面的因子 i 整除的方案数之和(容斥)

2.代码

#include<bits/stdc++.h>
using namespace std;
typedef double db;
typedef long long ll;
typedef vector<int> vi;
typedef pair<int, int> pii;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define pw(x) (1ll << (x))
#define sz(x) ((int)(x).size())
#define all(x) (x).begin(),(x).end()
#define rep(i,l,r) for(int i=(l);i<(r);++i)
#define per(i,l,r) for(int i=(r)-1;i>=(l);--i)
#define dd(x) cout << #x << " = " << x << ", "
#define de(x) cout << #x << " = " << x << endl
#define inv(x) qpow(x, MOD - 2)
//-----
const int N = 2e6 + 7, MOD = 1e9 + 7;
int add(int a, int b) { 
	if ((a += b) >= MOD) 
		a -= MOD; 
			return a; }								    //加法取模 
int mul(int a, int b) { return ll(a) * b % MOD; }       //乘法取模 
int qpow(int a, int b) { int r = 1; for (; b; b >>= 1) { if (b & 1) r = mul(r, a); a = mul(a, a); } return r; }
													 	//a^b取模 
int n, k;

int f[N], jc[N], ijc[N];								//f为fiboacci jc为阶乘,ijc为阶乘逆元 
int gao(int d) { return add(qpow(2, f[d] + (d <= 47 ? 0 : MOD - 1)), MOD - 1); }
														//score函数 
int C(int a, int b) { return mul(jc[a], mul(ijc[a - b], ijc[b])); }
														//c(a,b) % MOD 
void ini() {
	f[1] = 1; f[2] = 1;
	rep(i, 3, N) if ((f[i] = f[i - 2] + f[i - 1]) >= MOD - 1) f[i] -= MOD - 1;
	jc[0] = 1; rep(i, 1, N) jc[i] = mul(jc[i - 1], i);
	ijc[N - 1] = inv(jc[N - 1]); per(i, 0, N - 1) ijc[i] = mul(ijc[i + 1], i + 1);
	//rep(i, 0, 10) rep(j, 0, i + 1) cout << C(i, j) << " \n"[j == i];
}
int dp[N];
void solve() {
	cin >> n >> k;
	vi v;
	for (int i = 1; i * i <= n; i++) if (n % i == 0) {
		v.pb(i);
		if (i * i < n) v.pb(n / i);                  //压栈 
	}
	sort(all(v));                                   //排序函数 
	int ans = 0;
	per(i, 0, sz(v)) {
		int t = v[i];
		
		
		dp[i] = C(n / v[i] + k - 1, k - 1);
		per(j, i + 1, sz(v)) if (v[j] % v[i] == 0) dp[i] = add(dp[i], MOD - dp[j]);
		ans = add(ans, mul(gao(v[i]), dp[i]));
	}
	cout << mul(ans, inv(C(n + k - 1, k - 1))) << endl;
}
int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);								//lambda 表达式,可以立即执行,在main函数之前执行,取消输入输出同步,较快输入输出速度 
	ini();
	int tcas; cin >> tcas;
	rep(cas, 0, tcas) solve();
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值