ICPC 2019 银川 F - Function! 题解更好的阅读体验戳此进入题目链接题意前置知识反函数(逆函数)逆元分析简单的转换Tips
(建议您从上方链接进入我的个人网站查看此 Blog,在 Luogu 中图片会被墙掉,部分 Markdown 也会失效)
对于给定函数:
对于给定的
对于函数
对于本题的
对于
TODO
对于求逆元的方法,以及除数较小时如何不用逆元,这里不再赘述,以后有时间可能开个逆元的坑。
由前置知识可以得出题目中的式子等价于如下式子:
值得一提的是,本体因为输入数据只有一个数,所以可以考虑用数据库的思想,理论上在空间限制内,可以通过暴力程序,将结果以初始化数组的形式打印到文件里,这样的做法可以完全避免范围内的
显然直接枚举
考虑题中式子的性质:
显然我们可以看出显然有如下性质
则显然有
即
类比这个性质我们考虑
即
通过这两个性质原式可以转化为如下:
这里还可以继续化简,不过那就是常数问题了,显然现在这个式子可以直接
这时如果将
观察以

显然对于
显然对于每个区间的值域都有且只有一个值,即:
这样我们便可以以此为基础进行优化,将对应值乘上区间内值的数量在计算即可。
关于式子中的除法是否可以整除,可以从很多个角度来理解。
这部分很显然,具体做法不再赘述,将除法改为乘逆元即可。
如果按正解做会发现我们根本不需要计算 log 的值,所以不会有这个问题,但是如果选择
很多时候我们喜欢用换底公式来简单地表示出任意一个 log 的值,但是这样的求法对于单次使用精度还可以接受,但是对于本题,会随着 n 的增大逐渐放大这样做法的精度误差(我模拟赛的时候就因为这个而 0pts 了)。
不过这个我并没有想到高效且正确的方法,类似 BitScanReverse 这种的奇淫巧计也都是 VS 里面的,OI 用不了,能想到的只有用 long double 或者 float128 之类的东西,或者干脆递归手写求 log。
就像我写的正解里面被我注释掉的那一段代码,如果那一段的思路没有假掉了的话,那么就也是 log 炸精度了。
这道题里的
xxxxxxxxxx95123// #include <quadmath.h>4
56789
10/******************************11abbr12
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
242526272829
3031
3233
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 小优化