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\n",ans);
    }
    return 0;
}
C.<3 numbers

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

做法:约数个数小于3的数即质数。根据素数个数那个近似公式
\[ \pi(n) \text{~} \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\n");
        else {
            int cnt = 0;
            for(int i=l;i<=r;i++) {
                if(is_prime(i)) cnt++;
            }
            if(3*cnt < (r-l+1))  printf("Yes\n");
            else printf("No\n");
        }
    }
    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)) = \text{后面不写了你自己推吧} \]

#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(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\n",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\n");
        else printf("%d %d %d\n", 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\n",a+1,b+1);
        }
        else printf("%d\n",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

猜你喜欢

转载自www.cnblogs.com/bringlu/p/12526602.html