2019徐州区域赛 ACEFM 题解 & pollard-rho & miller-rabin & 求出每个子树的重心 板子

A. Cat

题目大意:你需要在 [L , R] 选取连续的一段,使得这一段的异或和小于给定的数 S. 请求出最长的长度。

做法:我们可以发现

[(2k) oplus (2k+1) = 1, (2k) oplus (2k+1) oplus (2k+2) oplus(2k+3) = 0 ]

,从一个奇数开始连续4个为0。那么我们就可以在一个小范围枚举左右端点,找出这连续最长的一段。代码是枚举 L ~ L+3 和 R-3 ~ R.

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define IL inline 
typedef long long LL;
int main() {
	int T; scanf("%d",&T);
	while(T--) {
		LL l,r,s; scanf("%lld%lld%lld",&l,&r,&s);
		LL ans = -1, now = 0;
		for(LL L=l;L<=l+3;L++) {
			for(LL R=r;R>=(r-3)&&R>=L;R--) {
				LL nowl = L, nowr; now = 0;
				if(L % 2 == 1) nowl = L + 1;
				nowr = nowl + (R-nowl+1) / 4 * 4 - 1;
				for(LL i=L;i<=nowl-1;i++) now ^= i;
				for(LL i=nowr+1;i<=R;i++) now ^= i;
				if(now <= s) ans = max(ans,R-L+1);
			}
		}
		printf("%lld
",ans);
	}
	return 0;
}
C.❤️ numbers

题目大意:给你一个区间 [L,R] ,你需要回答这个区间中约数个数小于 3 的数的个数是否小于 (frac{1}{3})

做法:约数个数小于3的数即质数。根据素数个数那个近似公式

[pi(n) ext{~} frac{n}{ln n} ]

可得,在大区间中,质数比例不可能大于 (frac{1}{3}) ,那么小区间特判一下即可。这里我设置的特判区间长度为100. 算法复杂度 (O(100T sqrt{n})) .

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
using namespace std;
#define IL inline
typedef long long LL;

IL bool is_prime(int x) {
	int m = sqrt(x+0.5);
	for(int i=2;i<=m;i++) {
		if(x % i == 0) return false;
	}
	return true;
}

int main() {
	int T; scanf("%d",&T);
	while(T--) {
		int l,r; scanf("%d%d",&l,&r);
		if(r-l+1>=100) printf("Yes
");
		else {
			int cnt = 0;
			for(int i=l;i<=r;i++) {
				if(is_prime(i)) cnt++;
			}
			if(3*cnt < (r-l+1))  printf("Yes
");
			else printf("No
");
		}
	}
	return 0;
}
E. Multiply

题目大意:给你 X,Y,a1,a2,..,an ,你需要求出最大的 i ,使得

[X^i | frac{Y!}{a_1!a_2!..a_n!} ]

由于题目中给出了 $Y >a_1+a_2+ .. + a_n! $ ,所以 $ a_1!a_2!..a_n! | Y! $,想证明的同学可以利用他们质因数的幂比大小去证明一下,这里就不写了。

我们对 X 做唯一分解,得到 X 的唯一分解式子。然后我们枚举 X 的每一个质因子,找到 (frac{Y!}{a_1!a_2!..a_n!}) 中能除以这个质因子多少次,再除以 X 中这个质因子的次数,最后取一个 min ,就是最后的答案。

由于 X 非常大,我们对 X 做唯一分解时需要使用到 Pollard-rho 算法和 Miller-Rabin 算法。然后还要再开一个map去存它的唯一分解式。

对了,还有 __int128 到底能不能在 windows 下运行啊...在本地测不得不让它变成 long long

所以最后的复杂度为

[O((k log^2 X + X^{frac{1}{4}}) log X + frac{log X}{log log X} log X + frac{log X}{log log X} cdot (n log a_i + log Y)) = ext{后面不写了你自己推吧} ]

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<map>
using namespace std;
#define IL inline
#define ri register int
typedef long long LL;
typedef unsigned long long ull;

const int N = 1e5 + 3;

IL void read(LL &x) {
	x=0; LL f=1; char ch = getchar();
	while(!isdigit(ch)) {if(ch == '-') f=-1;ch=getchar();}
	while(isdigit(ch)) { x=(x<<1)+(x<<3)+ch-'0'; ch=getchar();}
	x*=f;
}

LL gcd(LL a,LL b) { return b == 0 ? a : gcd(b,a%b);}
IL LL ksm(LL a,LL b,LL mod) {
	LL res = 1LL;
	while(b) {
		if(b&1LL) res = (__int128)res * a % mod;
		a = (__int128)a * a % mod;
		b >>= 1LL;
	}
	return res;
}

IL bool mr(LL x,LL b) {
    LL d=x-1, p=0;
    while((d&1)==0) d>>=1,++p;
    int i;
    LL cur=ksm(b,d,x);
    if(cur==1 || cur==x-1) return true;
    for(i=1;i<=p;++i) {
        cur=(__int128)cur*cur%x;
        if(cur==x-1) return true;
    }
    return false;
}

IL bool isprime(LL x) {
	if(x == 46856248255981 || x < 2) return false;
	if(x==2 || x==3 || x==7 || x==61 || x==24251) return true;
	return mr(x,2) && mr(x,3) && mr(x,7) && mr(x,61) && mr(x,24251);
}

IL LL f(LL x,LL c,LL mod) { return ((__int128)x*x+c) % mod;}
IL LL PR(LL x) {
	LL s=0,t=0,c=1LL*rand()%(x-1) + 1;
	LL val = 1LL;
	for(ri goal=1;;goal<<=1,s=t,val=1LL) {
		for(ri stp=1;stp<=goal;stp++) {
			t = f(t,c,x);
			val = (__int128)val * abs(t-s) % x;
			if(stp%127 == 0) {
				LL d = gcd(val,x);
				if(d > 1) return d;
			}
		}
		LL d = gcd(val,x);
		if(d > 1) return d;
	}
}

int faccnt = 0;
LL n,X,Y;
LL a[N],fac[N];
map<LL,LL> mp;

IL void getfac(LL x) {
        if(x == 1) return ;
	if(isprime(x)) fac[++faccnt] = x;
	else {
		LL d = x; while(d >= x) d = PR(x);
		getfac(d); getfac(x/d);
	}
}

IL LL cal(LL n,LL x) {
	LL ans = 0;
	while(n) {
		ans += n / x;
		n /= x;
	}
	return ans;
}

int main() {
	int T; scanf("%d",&T);
	while(T--) {
		mp.clear(); faccnt = 0;
		read(n); read(X); read(Y);
		for(int i=1;i<=n;i++) read(a[i]);
		getfac(X);
		for(int i=1;i<=faccnt;i++) mp[fac[i]]++;
		LL ans = 4e18;
		for(map<LL,LL>::iterator it=mp.begin();it!=mp.end();it++) {
			LL now = 0;
			for(int i=1;i<=n;i++) {
				now += cal(a[i], it->first);
			}
			ans = min(ans,(cal(Y,it->first)-now) / it->second);
		}
		printf("%lld
",ans);
	}
	return 0;
}
F. The Answer to the Ultimate Question of Life, The Universe, and Everything.

题意:给你 x ,你需要求出 a,b,c ,使其满足下式。

[a^3+b^3+c^3 = x ]

做法:打表题。枚举 a ~ [0,5000], b ~ [-5000,5000],得到一堆数。然后把这些数排序。再枚举 c 和 x ,得到 (c - x^3) ,然后在之前打出来的表二分查找这个数存不存在即可。

时间复杂度:(O(1e8 log 1e8))

代码与做法无关。

#include <bits/stdc++.h>

using namespace std;

int aa[] = {-5000,-5000,-4373,-5,210308,210308,-637,-169,-5000,-216,-650,-695,-11,210308,210308,-265,-4114,-3331,-1373,-95,-2816,-401,210308,210308,-10,-2683,-2107,-5000,-2268,-233,210308,210308,210308,210308,-1555,-1120,-3223,-444,-27,210308,210308,210308,210308,-823,-7,-2369,-758,-141,-3950,210308,210308,-796,210308,-2370,-3885,-3329,-672,-998,210308,210308,-1201,-966,-2744,-161,-5000,-929,1,210308,210308,-403,-2359,-533,-432,-335,210308,210308,210308,210308,-2080,-706,-1300,-2368,-1317,-3707,210308,210308,210308,-4126,-1390,-2514,-1803,-3389,-4052,-248,210308,210308,-22,-3168,-2101,-893,-1797,-2327,-239,210308,210308,-7,-2689,-1309,-1165,-2948,210308,-4793,210308,210308,210308,-12,-1906,-896,-4328,-3677,-2804,210308,210308,-37,-1,-5000,-2212,-4034,-3989,-1580,210308,210308,-1,-399,-3013,-1351,-1116,-758,-86,210308,210308,-139,-7,210308,-2746,-8,-327,-2366,210308,210308,-367,-463,-805,-3736,-2135,-3693,210308,210308,210308,-1534,-3874,-4767,-4125,-3423,-66,210308,210308,210308,-802,-1354,-3834,-1328,210308,210308,-335,210308,210308,-1168,-13,-2839,210308,-4874,-90,-4889,210308,210308,-4,-1885,-1639,-1702,-4812,-377,-20,210308,210308,210308,-1057,-2867,-3752,-2208,-2318};
int bb[] = {0,1,-486,4,210308,210308,-205,44,2,-52,-353,-641,7,210308,210308,-262,-588,2195,-1276,47,-741,-287,210308,210308,8,1839,237,3,-249,-69,210308,210308,210308,210308,-244,-509,2358,-84,16,210308,210308,210308,210308,-307,-5,1709,-473,49,-1247,210308,210308,602,210308,1518,-648,1837,505,361,210308,210308,-163,668,-1561,102,4,403,1,210308,210308,134,824,401,-104,-146,210308,210308,210308,210308,-829,-196,-706,-1719,847,1315,210308,210308,210308,-1972,-1282,1953,365,-2912,861,-98,210308,210308,14,-991,-1638,-622,-903,319,118,210308,210308,-4,-1165,947,-948,853,210308,-2312,210308,210308,210308,8,-757,-555,383,-1673,1219,210308,210308,-16,0,5,-419,-3881,-726,-1238,210308,210308,2,167,-1766,-629,816,-428,-77,210308,210308,104,-3,210308,-2552,-7,-263,1528,210308,210308,260,215,486,-695,-516,-1049,210308,210308,210308,383,-1654,-2476,-1417,-2943,-59,210308,210308,210308,-574,-1012,-2149,891,210308,210308,-170,210308,210308,-160,-10,1503,210308,974,-29,976,210308,210308,5,-1092,318,-1403,-593,-215,16,210308,210308,210308,-579,-1606,-1347,508,-638};

int cc[] = {5000,5000,4375,4,210308,210308,644,168,5000,217,683,843,10,210308,210308,332,4118,2977,1671,91,2833,445,210308,210308,8,2357,2106,5000,2269,235,210308,210308,210308,210308,1557,1154,2731,445,25,210308,210308,210308,210308,837,8,2025,815,139,3991,210308,210308,659,210308,2141,3891,3131,559,982,210308,210308,1202,845,2903,146,5000,903,4,210308,210308,398,2325,443,434,344,210308,210308,210308,210308,2123,711,1366,2638,1188,3651,210308,210308,210308,4271,1686,2036,1798,3992,4039,253,210308,210308,20,3200,2391,984,1870,2325,229,210308,210308,8,2760,1117,1345,2924,210308,4966,210308,210308,210308,11,1945,962,4327,3789,2725,210308,210308,38,5,5000,2217,4988,3997,1801,210308,210308,5,389,3203,1395,946,801,103,210308,210308,116,8,210308,3342,10,376,2131,210308,210308,317,447,741,3744,2145,3721,210308,210308,210308,1526,3972,4980,4180,4033,79,210308,210308,210308,890,1521,4047,1178,210308,210308,349,210308,210308,1169,15,2691,210308,4861,91,4876,210308,210308,5,2000,1635,1974,4815,399,16,210308,210308,210308,1112,3026,3809,2199,2334};


int main() {
	int T, x;
	scanf("%d", &T);
	while (T--) {
		scanf("%d", &x);
		if (aa[x] == 210308)
			printf("impossible
");
		else printf("%d %d %d
", aa[x], bb[x], cc[x]);
	}
	return 0;
}
H. Yuuki and a problem

题意:单点修改,查询用任意个一个区间的数相加最小不能被表示的数。

做法:听说要可持久化树套树?但是我还不会呢……先空着。

J. Loli, Yen-Jen, and a graph problem

题意:给出一个完全图,要将这张图分成 n−1 条路径,第 i 条路径的长度为 i,并且一条边只能存在于一条路径中。

做法:不会,以后也许会补,先空着。

M. Kill the tree

题意:给一棵树,求出每个子树的重心。

做法:从这棵树的叶子节点开始往上推出各个子树的重心。关于重心,我们有一条性质:以树的重心为根时,所有子树的大小都不超过整棵树大小的一半。假设我们当前要开始找以 u 节点为根的子树重心,已经把 u 的儿子们的重心都找出来了,那么以 u 节点为根的子树重心一定在重儿子子树重心到 u 的路径上。轻重链剖分一下即可。

代码与做法类似,但没有用到轻重链剖分。

最后要注意是要输出子树的全部重心,重心可能有两个。

#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;

const int N = 2e5 + 3;
vector<int> G[N];

int pa[N],ans[N],sz[N];

void dfs(int u,int fa) {
	pa[u] = fa; ans[u] = u; sz[u] = 1;
	for(int i=0;i<G[u].size();i++) {
		int v = G[u][i];
		if(v == fa) continue;
		dfs(v,u);
		sz[u] += sz[v];
	}
	for(int i=0;i<G[u].size();i++) {
		int v = G[u][i], ansv = ans[v];
		if(v == fa) continue;
		while(sz[ansv]*2 < sz[u]) ansv = pa[ansv];
		if(sz[ansv] < sz[ans[u]]) ans[u] = ansv;
	}
}

int main() {
	int n; scanf("%d",&n);
	for(int i=0,u,v;i<n-1;i++) {
		scanf("%d%d",&u,&v); u--; v--;
		G[u].push_back(v); G[v].push_back(u);
	}
	dfs(0,-1);
	for(int i=0;i<n;i++) {
		if(sz[ans[i]]*2 == sz[i]) {
			int a=ans[i], b=pa[ans[i]];
			if(a > b) swap(a,b);
			printf("%d %d
",a+1,b+1);
		}
		else printf("%d
",ans[i]+1);
	}
	return 0;
}

参考blog

https://www.cnblogs.com/Dup4/p/12005873.html
https://blog.csdn.net/qq_41157137/article/details/103440880
https://blog.csdn.net/weixin_40524635/article/details/103579292

原文地址:https://www.cnblogs.com/bringlu/p/12526602.html