zoukankan      html  css  js  c++  java
  • [十二省联考2019]骗分过样例

    传送门

      这道题是个毒瘤题,花费了我( ext{1day})独立解决(16)个子任务。下面步入正题。

    subtask 1-3:1_998244353

      这个观察数据不难得出要求(19^xmod 998244353),直接搞即可。注意到可能(x)非常大,根据费马小定理(x^{P-1} equiv 1 pmod P),我们需要读入取模

    subtask 4:1?

      观察数据和提示告诉我们:仍然求(19^x),只不过模数不知道。发现输出文件的最大值在(10^6)左右,我们拿第一个输入直接爆搜检验,最后能找出来(P=1145141)

    subtask 5:1?+

      这个是前一个的加强版,发现模数在(5 imes 10^{18})左右,这个不好暴力了。怎么办呢?我把输入的数排了个序,发现有两组输入的(x)之差为(2),于是我找到这两组对应的输出,得到了:(19^{264708066}equiv 1996649514996338529 pmod P)(19^{264708068}equiv 1589589654696467295 pmod P)。也就是说上面的式子乘上(19^2)再取模就能得到下面的数字,于是我们得到了:(1996649514996338529 imes 19^2 equiv 1589589654696467295 pmod P)。然后改写这个式子:(1996649514996338529 imes 361-nP=1589589654696467295),把常数移到右边,发现在(long long)范围内无法算出,我用(long double)算出了近似值。然后(P)一定是这个数的一个因子。发现(n)(100)(200)左右,我就暴力试除,考虑到精度又将(pm 1000)的模数用第一组输入输出判断了一下,最后找到了模数(P=5211600617818708273)

    subtask 6-7:1wa_998244353

      发现并不是求(19^x mod 998244353)了,换成了用(int)一步一步直接乘再取模,忽视溢出等问题。代码如下。

    	x = (int)(x * 19) % 998244353;
    

      第(6)个点直接顺序求解即可。第(7)个点恐怕不太行,(x)太大了。我一开始想改写快速幂来求解,发现行不通。正当我一筹莫展的时候,我让第(6)个点多跑到(10^6)组,发现了循环节。就是从(x=55246)开始,答案每过(45699)个数循环一次。这让我想起了( ext{Pollard-Rho})算法的( ho)。当然与那个算法没有关系,这里直接用上述性质即可。

    subtask 14-16:2g && 2g+

      当时我在做完前面(6)( ext{subtask})后紧接着做的。前面两个点,每次询问给你三个数(l)(r)(P),要求(l)(r)在模(P)下的原根。对于第(14)个点,(P=998244353)时,(varphi(P)=P-1=998244352=2^{23} imes 7 imes 17),因为不同的质因子只有(3)个,所以可以直接试除判断是否为原根。

      对于第(15)个点,(P=13123111)(varphi(P)=13123110=2×3×5×7×11×13×19×23),而且判断的数字多达(10^7)个,试除肯定会( ext{T})。我们可以利用其中一个原根把其他的原根遍历出来。在这里(g)(6),因为(g^t)遍历所有(varphi(P))个与(P)互质的数,而当且仅当(t)(varphi(P))互质的时候(g^t)也是原根。于是我们用(varphi(P))的质因子对(t)进行取模判断。遍历完后原根就找全了。

      对于第(16)个点,最后一组询问未知模数,根据数据给的原根我们反求模数。提示说在(10^9)(2 imes 10^9)之间且是个质数,我们一个一个找,然后借助已有的原根通过试除法判断这个质数可不可行。(forall g),如果(g^frac{P-1}{2} otequiv 1 pmod P),则(P)很可能是我们要找的模数。我的电脑跑了大约(5min)找到了一个数(P=1515343657),然后检验发现是正确的。用它搜原根与用(P=998244353)的方法一样。于是就解决了。

    subtask 8-10:2p

      要求我们判断(l)(r)内每个数是不是质数。小范围的可以用线性筛,范围稍微大点的可能可以筛一部分数然后用这部分数来筛(l)(r)。我直接上了( ext{Miller-Rabin}),这个算法可以在(log n)的时间内测试一个数是不是质数,正确率为(1-(frac{1}{4})^s)(s)为测试次数。这题貌似选取两三个数就可以了,这样常数小全能过。

    subtask 11-13:2u

      这里让我们筛出(l)(r)的莫比乌斯函数。

      同上面一样,我们可以小范围地筛出来(mu)过掉前两个点。当时我没有这么想,用了( ext{Pollard-Rho})来暴力分解然后筛出前(10^6)个莫比乌斯函数,发现第二个点都过不掉。怎么办呢?最大的数为(10^{18}),我想到如果筛出(10^6)以内的质数然后用这些质数来筛这些数,剩下的数的素因子一定(geq 10^6),所以剩下的数最多只能有两个素因子,也就是以下三种情况:

      一、剩下的数是质数,用( ext{Miller-Rabin})判一下,这个时候会使(mu)乘上(-1)

      二、剩下的数是两个不同的质数的乘积;负负得正,这个时候不会对(mu)产生贡献;

      三、剩下的数是一个质数的平方。这个时候(mu)(0)

      用小于(10^6)的因子去筛这些数,并且维护(mu),然后通过上面的三种情况分类讨论即可求解。

      但要注意要去掉含有平方因子的数。最后这道题就解完了。

    \ AC代码
    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define ll long long
    #define ull unsigned long long
    #define rep(i, a, b) for (register int i = a, end = b; i <= end; i++)
    #define repd(i, a, b) for (register int i = a, end = b; i >= end; i--)
    #define chkmax(a, b) a = max(a, b)
    #define chkmin(a, b) a = min(a, b)
    #define INF (1<<30)
    #define pb push_back
    #define mp(a, b) make_pair(a, b)
    #define fst first
    #define snd second
    #define pii pair<int, int>
    
    char s[15];
    
    namespace _998244353 {
    	int N;
    	ull P;
    	ull v;
    
    	inline void inc(ull &a, ull b, ull p) {
    		a += b;
    		if (a >= p) a -= p;
    	}
    
    	ull Mult(ull a, ull b, ull p) {
    		ull res = 0;
    		for (ull k = a; b; inc(k, k, p), b >>= 1)
    			if (b & 1) inc(res, k, p);
    		return res;
    	}
    
    	ull qpow(ull a, ull b, ull p) {
    		ull res = 1;
    		for (register ull k = a; b; k = Mult(k, k, p), b >>= 1)
    		if (b & 1) res = Mult(res, k, p);
    		return res;
    	}
    
    	inline ull read() {
    		ull w = 0; char c;
    		while (!isdigit(c = getchar())) ;
    		while (isdigit(c)) w = ((w << 3) + (w << 1) + (c ^ 48)) % (P-1), c = getchar();
    		return w;
    	}
    	void main(ull orz) {
    		P = orz;
    		scanf("%d", &N);
    		rep(i, 1, N) {
    			v = read();
    			printf("%llu
    ", qpow(19, v, P));
    		}
    	}
    }
    
    namespace WA {
    	int N;
    	int ans[55246+45699+5];
    	void main() {
    		scanf("%d", &N);
    		ans[0] = 1;
    		rep(i, 1, 55246+45699) {
    			ans[i] = (int)(ans[i-1]*19)%998244353;
    		}
    		rep(i, 1, N) {
    			ll val;
    			scanf("%lld", &val);
    			if (val <= 55246+45699) printf("%d
    ", ans[val]);
    			else printf("%d
    ", ans[(val-55246)%45699+55246]);
    		}
    	}
    }
    
    namespace GG {
    	int qpow(int a, int b, int p) {
    		int res = 1;
    		for (register int k = a; b; k = (ll)k*k%p, b >>= 1)
    			if (b & 1) res = (ll)res * k % p;
    		return res;
    	}
    	void run1(int l, int r, int p) {
    		if (p == 998244353) {
    			rep(i, l, r) if (qpow(i, 499122176, 998244353) != 1 && qpow(i, 142606336, 998244353) != 1 && qpow(i, 58720256, 998244353) != 1) printf("g"); else printf(".");
    		} else {
    			rep(i, l, r) 
    				if (qpow(i, 757671828, 1515343657) != 1 && qpow(i, 505114552, 1515343657) != 1 &&
    					qpow(i, 378552, 1515343657) != 1 && qpow(i, 96072, 1515343657) != 1) printf("g"); else printf(".");
    		}
    		puts("");
    	}
    	int st[13123120];
    	void run2(int p) {
    		memset(st, 0, sizeof(st));
    		int g = 6, cnt = 0;
    		do {
    			cnt++;
    			if (cnt % 2 && cnt % 3 && cnt % 5 && cnt % 7 && cnt % 11 && cnt % 13 && cnt % 19 && cnt % 23) st[g] = 1;
    			g = g*6%p;
    		} while (g != 6);
    		rep(i, 1, 13123110) if (st[i]) printf("g"); else printf(".");
    		puts("");
    	}
    }
    
    namespace PP {
    	inline ll Mult(ll a, ll b, ll p) {
    		ll c = (ll)a*b - (ll)((ull)((long double)a*b/p)*p);
    		return c < 0 ? c+p : ((ull)c >= (ull)p ? c-p : c);
    	}
    
    	ll qpow(ll a, ll b, ll p) {
    		ll res = 1;
    		for (register ll k = a; b; k = Mult(k, k, p), b >>= 1)
    			if (b & 1) res = Mult(res, k, p);
    		return res;
    	}
    	int test[10] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29};
    	bool MR(ll P, int cnt = 10) {
    		ll s = P-1; int t = 0;
    		while (!(s & 1)) s >>= 1, t++;
    		rep(i, 0, cnt-1) {
    			if (P == test[i]) return true;
    			if (test[i] > P) return false;
    			ll a = qpow(test[i], s, P), nxt;
    			rep(x, 1, t) {
    				nxt = Mult(a, a, P);
    				if (nxt == 1 && a != 1 && a != P-1) return false;
    				a = nxt;
    				if (a == 1) break;
    			}
    			if (a != 1) return false;
    		}
    		return true;
    	}
    	int N;
    	void main() {
    		scanf("%d", &N);
    		while (N--) {
    			ll l, r;
    			scanf("%lld%lld", &l, &r);
    			while (l <= r) {
    				if (MR(l)) printf("p"); else printf(".");
    				l++;
    			}
    			puts("");
    		}
    	}
    }
    
    namespace UU {
    	int N;
    	int check[1000005], p[100000];
    	void init() {
    		memset(check, 0, sizeof(check));
    		p[0] = 0;
    		rep(i, 2, 1000000) {
    			if (!check[i]) p[++p[0]] = i;
    			for (register int j = 1; j <= p[0] && i*p[j] <= 1000000; j++) {
    				check[i*p[j]] = 1;
    				if (!(i % p[j])) break;
    			}
    		}
    	}
    	ll frac[1000001], mu[1000001];
    	bool issqr(ll x) {
    		ll v = sqrt(x);
    		if (v*v == x || (v-1)*(v-1)==x || (v+1)*(v+1)==x) return true;
    		return false;
    	}
    #define cc(x) ((x) == 0 ? '0' : ((x) < 0 ? '-' : '+'))
    	void main() {
    		init();
    		scanf("%d", &N);
    		while (N--) {
    			ll l, r;
    			scanf("%lld%lld", &l, &r);
    			rep(i, 0, r-l) mu[i] = frac[i] = 1;
    			rep(i, 1, p[0]) {
    				ll x = 1ll*p[i]*p[i], st = l-(l-1)%x-1+x;
    				while (st <= r) {
    					mu[st-l] = 0; frac[st-l] = st; st += x;
    				}
    				x = p[i], st = l-(l-1)%x-1+x;
    				while (st <= r) {
    					mu[st-l] = -mu[st-l];
    					if (frac[st-l] != st) frac[st-l] *= x;
    					st += x;
    				}
    			}
    			for (register ll i = l; i <= r; i++) {
    				ll val = i/frac[i-l];
    				if (val == 1) printf("%c", cc(mu[i-l]));
    				else if (PP::MR(val, 2)) printf("%c", cc(-mu[i-l]));
    				else if (issqr(val)) printf("0");
    				else printf("%c", cc(mu[i-l]));
    			}
    			puts("");
    		}
    	}
    }
    
    int main() {
    	srand(time(0));
    	scanf("%s", s);
    	if (s[2] == '9') _998244353::main(998244353);
    	if (s[1] == '?') {
    		if (s[2] == '+') {
    			_998244353::main(5211600617818708273ll);
    		} else {
    			_998244353::main(1145141);
    		}
    	}
    	if (s[1] == 'w') {
    		WA::main();
    	}
    	if (s[1] == 'g') {
    		int l, r, p, N;
    		if (s[2] == '?') {
    			scanf("%d", &N);
    			while (N--) {
    				scanf("%d%d", &l, &r);
    				if (N) scanf("%d", &p); else p = 1515343657;
    				GG::run1(l, r, p);
    			}
    		} else {
    			scanf("%d", &N);
    			while (N--) {
    				scanf("%d%d%d", &l, &r, &p);
    				if (p == 998244353) GG::run1(l, r, p);
    				else GG::run2(p);
    			}
    		}
    	}
    	if (s[1] == 'p') {
    		PP::main();
    	}
    	if (s[1] == 'u') {
    		UU::main();
    	}
    
    	return 0;
    }
    
  • 相关阅读:
    Java控制台常用命令
    redis如何查看所有的key
    An internal error has occurred. Java heap space
    redis演练
    各种编程实现的树
    MYSQL两个数据库字符集保持一致问题
    进程控制之fork函数
    进程控制之进程标识符
    进程环境之getrlimit和setrlimit函数
    进程环境之setjmp和longjmp函数
  • 原文地址:https://www.cnblogs.com/ac-evil/p/11774865.html
Copyright © 2011-2022 走看看