P9920 「RiOI-03」变换,反演

提示:本题难度NOI/NOI+/CTSC较难,最好先学会方法再写。

题目背景

为了题目要求,我们对积性函数进行重定义:不保证 f(1)=1f(1)=1

题目描述

这是一道非传统题。

给定一个积性函数 f(d)f(d)。对于每一个测试点,我们会在附件中给出 g(n)=\sum_{d|n}f(d)g(n)=∑d∣n​f(d) 的其中 kk 项 \bmod\ 998244353mod 998244353 的值,这部分也会在输入中出现。接着,对于每一个测试点,有 tt 组数据。对于每组数据,输入 dd,请输出 f(d)\bmod998244353f(d)mod998244353 的值。

输入格式

第一行为 kk,接下来每一行会有两个正整数,分别为 dd 与 g(d)g(d)。

之后输入两个数 t,idt,id,分别表示数据组数与数据点编号。对于每组数据,输入一个正整数 nn。

输出格式

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

输入输出样例

输入 #1复制

10
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
10 10

3 -1
1
2
3

输出 #1复制

1
1
2

说明/提示

【样例解释】

由于 g(d)=dg(d)=d,因此 f(d)=\varphi(d)f(d)=φ(d),结果正确。

【数据范围】

对于每个测试点:

如果你正确回答了 n\le kn≤k 的测试数据,你将得到 20\%20% 的分数。

如果你正确回答了所有测试数据,你将得到剩余 80\%80% 的分数。所以,如果你无法正确回答,也请随机输出一个数来保证格式正确。

【数据范围】
\text{Id}Id\text{Name}Name\text{Score}Scoren\leqn≤k=k=t=t=
00\text{Epsilon}Epsilon5510^61061001001010
11\text{Division}Division5510^91091001001010
22\text{Unknown}Unknown5510^{18}1018111010
33\text{Random}Random101010^510510^510510^5105
44\text{Double}Double101010^91091001001010
55\text{Hack}Hack101010^9109316233162311
66\text{Square}Square151510^{18}101810010055
77\text{Poly}Poly202010^910910^5105100100
88\text{Thanks}Thanks202010^51054410^5105

附件下载

sum.zip1.53MB

上代码:

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef __int128 lll;

const int MAXN = 1e6 + 10;
const int mod = 998244353;

int k; ll f[MAXN];

namespace Sub0 {
	
	inline 
	ll solve(ll n) {
		int res = 0;
		for (ll i = 2; i <= n; i++) {
			if (n % i) continue;
			if (n / i % i) n /= i, res ^= 1;
			else return 0;
		}
		if (n > 1) res ^= 1;
		return res ? mod - 1 : 1;
	}
	
}

namespace Sub1 {
	
	inline 
	ll solve(ll n) {
		return 1;
	}
	
}

namespace Sub2 {
	
	inline 
	ll solve(ll n) {
		return 0;
	}
	
}

namespace Sub3 {
	
	bool d = 1;
	
	inline 
	void init() {
		for (int i = 1; i <= k; i++) {
			for (int j = i << 1; j <= k; j += i) f[j] = (f[j] - f[i] + mod) % mod;
		}
	}
	
	inline 
	ll solve(ll n) {
		if (d) init(), d = 0;
		return f[n];
	}
	
}

namespace Sub4 {
	
	inline 
	ll phi(int n) {
		int res = n;
		for (int i = 2; i <= n / i; i++) {
			if (n % i == 0) for (res -= res / i; n % i == 0; n /= i);
		}
		if (n > 1) res -= res / n;
		return (ll)res * res % mod;
	}
	
	inline 
	ll solve(ll n) {
		ll ans = 0;
		for (int i = 1; i <= n / i; i++) {
			if (n % i) continue;
			ans = (ans + phi(i)) % mod;
			if (i != n / i) ans = (ans + phi(n / i)) % mod;
		}
		return ans;
	}
	
}

namespace Sub5 {
	
	inline 
	void init() {
		for (int i = 1; i <= k; i++) {
			for (int j = i << 1; j <= k; j += i) f[j] = (f[j] - f[i] + mod) % mod;
		}
	}
	
	inline 
	ll solve(ll n) {
		init();
		for (int i = 2; i <= n / i; i++) {
			if (n % i == 0) return f[i] * f[n / i] % mod;
		}
	}
}

namespace Sub6 {
	
	const int prime[] = { 2, 3, 5, 7, 11, 61, 24251 };
	
	mt19937 eng(time(0));
	
	inline 
	ll randint(ll l, ll r) {
	    uniform_int_distribution<ll> dis(l, r);
	    return dis(eng);
	}
	
	inline 
	ll qpow(ll b, ll p, ll mod) {
		ll res = 1;
		while (p) {
			if (p & 1) res = (lll)res * b % mod;
			b = (lll)b * b % mod, p >>= 1;
		}
		return res;
	}
	
	inline 
	bool check(ll a, ll p) {
		ll s = p - 1, k;
		for (; ~s & 1; s >>= 1);
		for (k = qpow(a, s, p); s != p - 1 && k != 1 && k != p - 1; k = (lll)k * k % p, s <<= 1);
		return k == p - 1 || s & 1;
	}
	
	inline 
	bool isprime(ll n) {
		if (n == 1) return 0;
		for (int i = 0; i < 7; i++) {
			if (n == prime[i]) return 1;
			if (n % prime[i] == 0) return 0;
			if (!check(prime[i], n)) return 0;
		}
		for (int i = 1; i <= 10; i++) if (!check(randint(2, n - 1), n)) return 0;
		return 1;
	}
	
	inline 
	ll pollard_rho(ll n) {
	    if (n == 4) return 2;
	    if (isprime(n)) return n;
	    for (ll c, t, r, p, q; ;) {
	        c = randint(1, n - 1), t = 0, r = 0, p = 1, q;
	        auto f = [=](ll x) { return ((lll)x * x + c) % n; };
	        do {
	            for (int i = 0; i < 128; ++i) {
	                t = f(t), r = f(f(r));
	                if (t == r || (q = (lll)p * abs(t - r) % n) == 0) break; p = q;
	            }
	            ll d = __gcd(p, n); if (d > 1) return d;
	        } while (t != r);
	    }
	}
	
	unordered_map<ll, ll> mp;
	
	ll get(ll x) {
	    if (mp[x]) return mp[x];
	    ll k = pollard_rho(x);
	    return mp[x] = k == x ? x : mp[x] = max(get(k), get(x / k));
	}
	
	inline 
	void print(lll n) {
		if (n < 10) return putchar(n ^ '0'), void();
		print(n / 10), putchar(n % 10 ^ '0');
	}
	
	inline 
	ll solve(ll n) {
		lll res = (lll)n * n;
		for (ll k = get(n); ; k = get(n)) {
			for (res -= res / k / k; n % k == 0; n /= k);
			if (n == 1) break;
		}
		mp.clear();
		return res % mod;
	}
}

namespace Sub7 {
	
	inline 
	ll calc(ll n) {
		ll ans = 114;
		ans = (ans * n + 514) % mod;
		ans = (ans * n + 1919) % mod;
		ans = (ans * n + 810) % mod;
		return ans;
	}
	
	inline 
	ll solve(ll n) {
		ll ans = 1;
		for (ll i = 2, k; i <= n / i; i++) {
			for (k = 1; n % i == 0; n /= i, k *= i);
			if (k > 1) ans = ans * calc(k) % mod;
		}
		if (n > 1) ans = ans * calc(n) % mod;
		return ans;
	}
}
namespace Sub8{
	inline 
	ll solve(ll n){
		return n*n%3;
	}
	
}
typedef ll(*funcs)(ll);
funcs solve[9]={ 
	Sub0::solve,Sub1::solve,Sub2::solve,Sub3::solve,Sub4::solve,Sub5::solve,Sub6::solve,Sub7::solve,Sub8::solve 
};
ll n; 
int t,id;
int main(){
	scanf("%d",&k);
	for(int i=1;i<=k;i++)scanf("%*d%lld",&f[i]);
	for(scanf("%d%d",&t,&id);t--;scanf("%lld",&n),printf("%lld\n",solve[id](n)));
}

制作不易,给个关注吧哥!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值