• 【NOI模拟赛】思门弄数(数论,链表)


    题目背景

    永远的神 OneInDark 出了一道没人做得出来的线性代数题,在用这道题击败 EI 大师后,跑到 crashed 门前求战。

    但是没想到,crashed 还没完全推开门时,这道题就被祂干碎了,这超出了 OneInDark 对于祂秒切的预期。

    “只给我找些线性代数题,这是在看不起我吗!” crashed 怒吼道。话音未落,二神就出现在了思门擂台上。

    “看好了,我这次给你出道函数题!……”

    OneInDark 端详了一秒,发现不对劲了,“嗯?这不是道生成函数!”

    “你已经过了一秒了!哈哈!被创了吧!” crashed 大笑。

    但是 OneInDark 立刻超光速把这题切了,使得最终完成时间变成了 − 1   m s -1\rm\,ms 1ms

    题面

    定义函数 F ( x ) = ∏ k = 0 ⌊ x − 1 ⌋ ( x − k 2 ) F(x)=\prod_{k=0}^{\lfloor\sqrt{x-1}\rfloor} (x-k^2) F(x)=k=0x1 (xk2) ,求在 [ l , r ] [l,r] [l,r] 中有多少个正整数 x x x 满足 F ( x ) F(x) F(x) m m m 的倍数。

    输入一行 l r m ,输出一行答案。

    限制: 1 ≤ l ≤ r ≤ 1 0 12 , 2 ≤ m ≤ 1 0 6 1\leq l\leq r\leq 10^{12},2\leq m\leq 10^6 1lr1012,2m106 ,1 s,128 mb 。

    样例

    1 1000000000000 1000000
    
    • 1
    599999999844
    
    • 1

    题解

    当你完全用做数学题推式子的脑子想这道题,你就输了。

    我们不妨修改成 F ( x ) = ∏ k = 0 ⌊ x − 1 ⌋ ( ( x − k 2 ) m o d    m ) F(x)=\prod_{k=0}^{\lfloor\sqrt{x-1}\rfloor} ((x-k^2)\mod m) F(x)=k=0x1 ((xk2)modm) ,于是不难发现, F ( x + m ) F(x+m) F(x+m) 一定是 F ( x ) F(x) F(x) 的倍数

    这就意味着,取模 m m m 相等的一系列 x x x ,在 F ( x ) F(x) F(x) 是否是 m m m 的倍数这一问题上是单调的。

    所以,我们可以求每一个同余类的最小的 x x x 满足 F ( x ) F(x) F(x) m m m 的倍数。又因为一个 k 2 k^2 k2 对于一个同余类的所有数贡献是相等的,所以我们只需要求出 k 2 k^2 k2 小于该 x x x 的最大的 k k k 就行了。

    我们从小到大枚举 k k k ,并统计 k k k 的贡献。但是这样暴力是会超时的。

    我们不妨将 m m m 质因数分解, m = ∏ p i w i m=\prod p_i^{w_i} m=piwi,对于每个 p i p_i pi 单独考虑枚举 k k k 算贡献,求出各个同余类包含 p i w i p_i^{w_i} piwi 的最小时间戳,最后再对每个同余类求时间戳的最大值。

    这样每次枚举 k k k 的时候,从 k 2 m o d    m k^2\mod m k2modm 开始跳,每次往后跳 p i p_i pi 长度,用链表维护并 O ( 1 ) O(1) O(1) 跳过所有已经包含 p i w i p_i^{w_i} piwi 的位置,暴力乘贡献。由于每次计算都会使得一个同余类的 p i p_i pi 次数增加,最终到达 p i w i p_i^{w_i} piwi 停止,可以证明时间复杂度是 O ( m log ⁡ m ) O(m\log m) O(mlogm) 的。

    总算法时间复杂度 O ( m log ⁡ m + r log ⁡ m ) O(m\log m+\sqrt{r}\log m) O(mlogm+r logm)

    CODE

    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #pragma GCC optimize(2)
    using namespace std;
    #define MAXN 1000005
    #define LL long long
    #define ULL unsigned long long
    #define ENDL putchar('\n')
    #define DB double
    #define lowbit(x) (-(x) & (x))
    #define FI first
    #define SE second
    #define PR pair<int,int>
    #define UIN unsigned int
    int xchar() {
    	static const int maxn = 1000000;
    	static char b[maxn];
    	static int pos = 0,len = 0;
    	if(pos == len) pos = 0,len = fread(b,1,maxn,stdin);
    	if(pos == len) return -1;
    	return b[pos ++];
    }
    // #define getchar() xchar()
    inline LL read() {
    	LL f = 1,x = 0;int s = getchar();
    	while(s < '0' || s > '9') {if(s<0)return -1;if(s=='-')f=-f;s = getchar();}
    	while(s >= '0' && s <= '9') {x = (x<<1) + (x<<3) + (s^48);s = getchar();}
    	return f*x;
    }
    void putpos(LL x) {if(!x)return ;putpos(x/10);putchar((x%10)^48);}
    inline void putnum(LL x) {
    	if(!x) {putchar('0');return ;}
    	if(x<0) putchar('-'),x = -x;
    	return putpos(x);
    }
    inline void AIput(LL x,int c) {putnum(x);putchar(c);}
    
    int MOD = 1;
    int n,m,s,o,k;
    int dp[MAXN],f[MAXN];
    LL c[MAXN];
    PR fct[MAXN];
    int hd[MAXN],nx[MAXN];
    int main() {
    	LL l = read(),r = read();MOD = read();
    	int nn = MOD;
    	for(int i = 2;i*i <= nn;i ++) {
    		if(nn % i == 0) {
    			int ct = 0;
    			while(nn % i == 0) nn /= i,ct ++;
    			fct[++ m] = {i,ct};
    		}
    	}
    	if(nn > 1) fct[++ m] = {nn,1};
    	for(int i = 1;i <= m;i ++) {
    		int x = fct[i].FI,w = fct[i].SE,xx = 1;
    		for(int j = 0;j < w;j ++) xx *= x;
    		for(int j = 0;j < x;j ++) hd[j] = -1;
    		for(int j = 0;j < MOD;j ++) {
    			f[j] = 1000001,c[j] = 1;
    			nx[j] = hd[j%x]; hd[j%x] = j;
    		}
    		for(int j = 0;j*1ll*j < r;j ++) {
    			int ad = j*1ll*j%x,po = j*1ll*j%MOD;
    			vector<int> emp;
    			int tl = hd[ad]; hd[ad] = -1;
    			for(int y = tl;y>=0;y = tl) {
    				tl = nx[y];
    				int le = (y+MOD-po)%MOD;
    				(c[y] *= le) %= MOD;
    				if(c[y] % xx == 0) f[y] = j;
    				else nx[y] = hd[ad],hd[ad] = y;
    			}
    		}
    		for(int j = 0;j < MOD;j ++) {
    			dp[j] = max(dp[j],f[j]);
    		}
    	}
    	LL ans = 0;
    	for(int i = 0;i < MOD;i ++) {
    		LL st = dp[i]*1ll*dp[i]+1;
    		st = st + (MOD-st%MOD+i)%MOD;
    		if(st <= r) ans += (r-st)/MOD+1;
    		if(st < l) ans -= (l-1-st)/MOD+1;
    	}
    	AIput(ans,'\n');
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
  • 相关阅读:
    Java 基础 进程与线程
    【往届均已检索】2022年视觉,图像与信号处理国际会议(ICVISP 2022)
    接口和接口测试
    Revit翻模教程:怎么在体量内绘制圆锥?
    Android之OKHttp源码解析
    Dubbo 3 易用性升级之 Dubbo 官网大改版
    文件系统.
    垃圾收集算法
    C++之函数重载【详解】
    【JWT】解密JWT:让您的Web应用程序更安全、更高效的神秘令牌
  • 原文地址:https://blog.csdn.net/weixin_43960414/article/details/125881149