校测 2024 0930 数学

0-30-0,数学还只打了暴力,菜就多练

Problem 1. facsum

省流: $$f(n) =(\sum\limits_{d\mid n}\varphi(d))^m(\sum\limits_{d\mid n}\sigma_0(d)\mu(\frac{n}{d})\frac{n}{d})$$
\(\sum\limits_{i = 1}^nf(i)\bmod 1e9+7\)
大概是把 \(\sum\limits_{i=1}^n\) 拆开,打表找规律,分组线性筛
前面的区域以后再来探索吧

Problem 2. group

Mr.Hu 最近在研究等比数列,即形如:

\[a^1, a^2,...,a^n,... \]

现在,Mr.Hu 想知道,对于给定的非负整数 \(a\),上面这个无穷数列在摸 \(mod\) 意义下有多少项是本质不同
的。(保证 \(gcd(a, mod) = 1\))。

Input

第 1 行一个整数:\(T\) ,表示数据组数。接下来 \(T\) 行,每行两个整数:\(a, mod\)

Output

对于每组数据,输出一行,包含一个整数,表示模意义下本质不同的数有多少个。

Note

• 对于 30% 的数据,\(0 ≤ a ≤ 1e3,1 ≤ mod ≤ 1e3\)
• 对于 100% 的数据,\(0 ≤ a ≤ 2 × 1e9,1 ≤ mod ≤ 2 × 1e9,且保证 gcd(a, mod) = 1,1 ≤ T ≤ 100。\)

分析

对于模意义下的等比数列最小循环节长度,考虑循环节到最后一项必定为 \(1\) , 想到欧拉定理 \(a^{\varphi(n)}\equiv 1 \pmod p\),直接暴力求 \(\varphi(n)\) ,枚举其因子 \(x\) 是否满足 \(a^x\equiv 1 \pmod p\),快速幂优化一下,时间复杂度 \(O(T\sqrt n\log(m))\)

AC代码:

#include<bits/stdc++.h>
using namespace std;

inline int read() {
	int f = 1, otto = 0;
	char a = getchar();
	while(!isdigit(a)) {
		if(a == '-') f = -1;
		a = getchar();
	}
	while(isdigit(a)) {
		otto = (otto << 1) + (otto << 3) + (a ^ 48);
		a = getchar();
	}
	return f * otto;
} 

int a, mod;
int ans = 0;

int getphi(int x) {
	int as = x;
	for(int i = 2; i * i<= x; i++) {
		if(x % i == 0) {
			while(x % i == 0) x /= i;
			as = as / i * (i - 1) ;	//公式 
		}
	}
	if(x > 1) as = as / x * (x - 1);
	return as;
}

int qpow(long long x, int y) {
	long long as = 1;
	while(y) {
		if(y & 1) (as *= x) %= mod, y--;
		(x *= x) %= mod, y >>= 1;
	}
	return as;
}

void solve() {
	if(a == 0) return printf("0\n"), void(0);
	int phi = getphi(mod); 
	ans = phi;
	for(int i = 1; i * i <= phi; i++) {
		if(phi % i == 0){
			if(qpow(a, i) == 1) ans = min(ans, i);
			else if(qpow(a, phi / i) == 1) ans = min(ans, phi / i);
		}
		
	}
	return printf("%lld\n", ans), void(0);
}

int main() {
	freopen("group.in", "r", stdin);
	freopen("group.out", "w", stdout);
	int T = read();
	while(T--) {
		a = read(), mod = read();
		solve();
	}
	return 0;
}

Problem 3. ccount

Mr.Hu 最近在学习组合数,他觉得这些数非常美丽。
于是,他写下了这样一个数列:

\[\binom{n}{l},\binom{n}{l + 1},\binom{n}{l + 2}, ...,\binom{n}{r - 1},\binom{n}{r} \]

Mr.Hu 想知道,这些数里面,有多少个数是 \(5\) 的倍数。

Input

第 1 行一个整数:\(T\) ,表示数据组数。
接下来 \(T\) 行,每行三个整数:\(l,r,n\)

Output

对于每组数据,输出一行,包含一个整数,表示答案。

Note

• 对于 20% 的数据,\(1 ≤ n ≤ 5000\)
• 对于 40% 的数据,\(1 ≤ n ≤ 1e9,1 ≤ r − l + 1 ≤ 5000\)
• 对于 100% 的数据,\(1 ≤ n ≤ 1e18,0 ≤ l ≤ r ≤ n,1 ≤ T ≤ 100\)

分析

由于 \(l, r\) 长度很大,不能直接做, 考虑转换。求组合数是 \(5\) 的倍数的个数, 即求:

\[\sum \limits_{i = l}^r [\binom{n}{i}\bmod 5=0] \]

由于 \(5\) 是质数,根据 \(Lucas\) 定理,可以拆成:$$\sum \limits_{i = l}^r [\binom{\lfloor
\frac{n}{5^x} \rfloor}{\lfloor
\frac{i}{5^x}\rfloor}\cdot\binom{\lfloor
\frac{n}{5^{x-1}}\rfloor\bmod5}{\lfloor
\frac{i}{5^{x-1}}\rfloor\bmod5}\cdot...\cdot\binom{\lfloor
\frac{n}{5^{1}}\rfloor\bmod5}{\lfloor
\frac{i}{5^{1}}\rfloor\bmod5}\cdot\binom{
n\bmod5}{
i\bmod5 }\bmod 5=0]$$
即 $$n=(a_1a_2a_3...a_x)_5$$

\[i=(b_1b_2b_3...b_x)_5 \]

要使 \(\binom{n}{i}\bmod5=0\) 当且仅当 \(\exists b_j > a_j\) ,考虑在五进制下做数位DP

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

inline ll read() {
	ll f = 1, otto = 0;
	char a = getchar();
	while(!isdigit(a)) {
		if(a == '-') f = -1;
		a = getchar();
	}
	while(isdigit(a)) {
		otto = (otto << 1) + (otto << 3) + (a ^ 48);
		a = getchar();
	}
	return f * otto;
}

ll dp[30][30], a[30], b[30];
ll l, r, n, lena, lenb, ans;

ll dfs(int pos, int r, int lim) {
	if(!lim && dp[pos][r] != -1) return dp[pos][r];
	if(pos == 0) return r == 1 ? 1 : 0;
	ll ret = 0;
	int num = lim ? b[pos] : 4;
	for(int i = 0; i <= num; i++) {
		ret += dfs(pos - 1, r || (i > a[pos]), lim && i == num);
	}
	if(!lim) dp[pos][r] = ret;
	return ret;
}

void part(ll x) {
	lenb = 0;
	memset(dp, -1, sizeof dp);
	while(x) {
		b[++lenb] = x % 5, x /= 5;
	}
	ans = dfs(lenb, 0, 1);
	return;
}

void solve() {
	lena = 0;
	memset(a, 0, sizeof a);
	memset(b, 0, sizeof b);
	while(n) a[++lena] = n % 5, n /= 5;
	part(r); ll ansr = ans;
	if(l) {part(l - 1); ansr -= ans;}
	printf("%lld\n", ansr);
	return;
}

int main() {
	freopen("ccount.in", "r", stdin);
	freopen("ccount.out", "w", stdout); 
	ll T = read();
	while(T--) {
		l = read(), r = read(), n = read();
		solve();
	}
	return 0;
} 
posted @ 2024-09-30 21:25  Ydoc770  阅读(27)  评论(0)    收藏  举报