ICPC 2019 银川 F - Function! 题解更好的阅读体验戳此进入题目链接题意前置知识反函数(逆函数)逆元分析简单的转换Tips
(建议您从上方链接进入我的个人网站查看此 Blog,在 Luogu 中图片会被墙掉,部分 Markdown 也会失效)
对于给定函数:
对于给定的
对于函数
对于本题的
对于
TODO
对于求逆元的方法,以及除数较小时如何不用逆元,这里不再赘述,以后有时间可能开个逆元的坑。
由前置知识可以得出题目中的式子等价于如下式子:
值得一提的是,本体因为输入数据只有一个数,所以可以考虑用数据库的思想,理论上在空间限制内,可以通过暴力程序,将结果以初始化数组的形式打印到文件里,这样的做法可以完全避免范围内的
显然直接枚举
考虑题中式子的性质:
显然我们可以看出显然有如下性质
则显然有
即
类比这个性质我们考虑
即
通过这两个性质原式可以转化为如下:
这里还可以继续化简,不过那就是常数问题了,显然现在这个式子可以直接
这时如果将
观察以
显然对于
显然对于每个区间的值域都有且只有一个值,即:
这样我们便可以以此为基础进行优化,将对应值乘上区间内值的数量在计算即可。
关于式子中的除法是否可以整除,可以从很多个角度来理解。
这部分很显然,具体做法不再赘述,将除法改为乘逆元即可。
如果按正解做会发现我们根本不需要计算 log 的值,所以不会有这个问题,但是如果选择
很多时候我们喜欢用换底公式来简单地表示出任意一个 log 的值,但是这样的求法对于单次使用精度还可以接受,但是对于本题,会随着 n 的增大逐渐放大这样做法的精度误差(我模拟赛的时候就因为这个而 0pts 了)。
不过这个我并没有想到高效且正确的方法,类似 BitScanReverse 这种的奇淫巧计也都是 VS 里面的,OI 用不了,能想到的只有用 long double 或者 float128 之类的东西,或者干脆递归手写求 log。
就像我写的正解里面被我注释掉的那一段代码,如果那一段的思路没有假掉了的话,那么就也是 log 炸精度了。
这道题里的
xxxxxxxxxx
951
2
3// #include <quadmath.h>
4
5
6
7
8
9
10/******************************
11abbr
12
13******************************/
14
15using namespace std;
16
17mt19937 rnd(random_device{}());
18int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
19
20typedef unsigned int uint;
21typedef unsigned long long unll;
22typedef long long ll;
23
24
25
26
27
28
29
30
31
32
33
34int qpow(int a, int b){
35 ll ret(1), mul(a);
36 while(b){
37 if(b & 1)ret = ret * mul % MOD;
38 b >>= 1;
39 mul = mul * mul % MOD;
40 }
41 return int(ret);
42}
43
44const int inv_2 = qpow(2, MOD - 2);
45const int inv_6 = qpow(6, MOD - 2);
46
47ll CalFunc(ll n){
48 ll left = (n + 1) % MOD * (ll)inv_2 % MOD * ((sqrtN + n + 1)%MOD) % MOD * (ll(-sqrtN + n)%MOD) % MOD;
49 ll rightl = n % MOD * ((n + 1) % MOD) % MOD * ((2 * n + 1) % MOD) % MOD * inv_6 % MOD;
50 ll rightr = sqrtN % MOD * ((sqrtN + 1)%MOD) % MOD * ((2 * sqrtN + 1)%MOD) % MOD * (inv_6 % MOD) % MOD;
51 ll right = (rightl - rightr + MOD) % MOD;
52 return (left - right + MOD) % MOD;
53}
54
55template<typename T = int>
56inline T read(void);
57
58signed main(){
59 int N = read();
60 int ans(0ll);
61 for(int a = 2; a * a <= N; ++a){
62 // int tmpp(0);
63 // for(int k = 1; k < logg(a, N); ++k){
64 // int tmp = (qpow(a, k + 1) - qpow(a, k) + MOD) % MOD;
65 // tmpp = (tmpp + tmp) % MOD;
66 // }
67 // tmpp = ((N - qpow(a, logg(a, N)) + 1) % MOD + tmpp) % MOD;
68 // ans = (ans + tmpp * a % MOD) % MOD;
69 ll tmp(1ll);
70 for(int b = a; b <= N; b *= a, ++tmp){
71 ans = (ans + (min(b * a - 1, N) - (b - 1) + MOD) % MOD * tmp % MOD * a % MOD) % MOD;
72 }
73 }
74 ans = (ans + CalFunc(N)) % MOD;
75
76 printf("%lld\n", ans);
77 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
78 return 0;
79}
80
81template<typename T>
82inline T read(void){
83 T ret(0);
84 short flag(1);
85 char c = getchar();
86 while(c != '-' && !isdigit(c))c = getchar();
87 if(c == '-')flag = -1, c = getchar();
88 while(isdigit(c)){
89 ret *= 10;
90 ret += int(c - '0');
91 c = getchar();
92 }
93 ret *= flag;
94 return ret;
95}
update-2022_08_25 初稿
update-2022_08_25 小优化