1月8日

思维题训练

https://codeforces.com/contest/1800/problem/E1

https://codeforces.com/contest/1800/problem/E2

这两题很经典,两点间的交换看作两点在一个连通块,用并查集建边。

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e6+10;
int fa[N];
int find(int x){
    if(x==fa[x]) return x;
    return fa[x]=find(fa[x]);
}
void unset(int x,int y){
    fa[find(x)]=find(y);
}

void solve() {
    int n, k;
    cin >> n >> k;
    string s, t;
    cin >> s >> t;
    s = " " + s;
    t = " " + t;
    for (int i = 1; i <= n; i++) {
        fa[i] = i;
    }
    for (int i = 1; i <= k; i++) {
        for (int j = i; j + k <= n; j += k) {
            unset(j, j + k);
        }
        for (int j = i; j + k + 1 <= n; j += (k + 1))
            unset(j, j + k + 1);
    }
    map<int, map<char, int>> mp;
    map<int, map<char, int>> mp1;
    for (int i = 1; i <= n; i++) {
        int fx = find(i);
        mp[fx][s[i]]++;
        mp1[fx][t[i]]++;
    }
    for (auto i: mp) {
        int th = i.first;
        for (auto j: mp[th]) {
            if (mp1[th][j.first] != j.second) {
                cout << "NO" << endl;
                return;
            }
        }
    }
    cout << "YES" << endl;
}

signed main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int t;
    cin >> t;
    while (t--)
        solve();
    return 0;
}
else

How Many Answers Are Wrong - HDU 3038 - Virtual Judge

题意:有一段未知的序列,每次给出序列中某个区间的左右端点以及区间和,判断给出的是否正确

思路:可以将区间的右端点视为父亲节点,区间和是为边的权值,用带权值的并查集建边。

#include <bits/stdc++.h>
//#define int long long
#define endl '\n'
using namespace std;
//typedef unsigned __int128 LL;
const int N=2e5+10,M=1e6+10,inf=1e16,mod=1e8;
int fa[N];
int W[N];
int find(int x){
    if(x==fa[x]) return x;
    else{
        int tmp=fa[x];
        fa[x]=find(fa[x]);
        W[x]+=W[tmp];
        return fa[x];
    }
}
void solve() {
    int n, m;
    while (cin >> n >> m) {
        int ans = 0;
        for (int i = 1; i <= n+1; i++) {
            W[i] = 0;
            fa[i] = i;
        }
        for (int i = 1; i <= m; i++) {
            int x, y, w;
            cin >> x >> y >> w;
            y++;
            int fx = find(x);
            int fy = find(y);
            if (fx != fy) {
                fa[fx] = fy;
                W[fx] = W[y] + w - W[x];
            } else {
                if (W[x] - W[y] != w) ans++;
            }
        }
        cout << ans << endl;
    }
}

signed main() {
    ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
//    int _;
//    cin >> _;
//    while (_--)
        solve();
    return 0;
}

[P8795 蓝桥杯 2022 国 A] 选素数 - 洛谷 | 计算机科学教育新生态

用欧拉筛求出每个点的最大质因子。

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define ll long long
#define lll __int128
int MOD=1e9+7;
const int N=1e6+10;
inline int read(){//inline是内联函数,可以稍微加快一点速度(写不写均可)
    int x = 0, f = 1;//x是我们最终要返回的变量里的值,f用来表示正负(1为正,-1为负)
    char ch = getchar();//使用字符读入,这也是快读快的本质
    while(ch < '0' || ch > '9'){//用于处理输入时的一些前置无意义字符
        if(ch == '-'){//是负号
            f = -1;
        }
        ch = getchar();//循环读入
    }
    while(ch >= '0' && ch <= '9'){//读入数(只有数字的部分,不区分正负)
        x = x * 10 + (ch - '0');//跟数位拆分很像
        ch = getchar();
    }
    return x * f;//当f = -1是返回值就会变成与输入值相同的负数
}
inline void write(int x){
    if(x < 0){//是负数提前输出负号
        putchar('-');//字符输出
        x = -x;//转成正数处理
    }
    if(x > 9){//不是一位数
        write(x / 10);//递归——直到最高位
    }
    putchar(x % 10 + '0');//转成字符输出
}

inline int Abs(int x) { return x < 0 ? -x : x; }  //取绝对值
inline int gcd(int x, int y) {                     //非递归求gcd
    int z;
    while (y) {
        z = x;
        x = y;
        y = z % y;
    }
    return x;
}
int lowpow(int a,int b,int mod)
{
    int tp=a;
    int num=0;
    while(b)
    {
        if(b&1)num+=tp;num%=mod;
        tp*=2;tp%=mod;b/=2;
    }
    return num;
}
int goodpow(int a,int b,int mod)
{
    int tp=a;
    int num=1;
    while(b)
    {
        if(b&1)num=lowpow(num,tp,mod);num%=mod;
        tp=lowpow(tp,tp,mod);tp%=mod;b/=2;
    }
    return num;
}

inline bool mr(int x, int p) {              // mille rabin判质数
    if (goodpow(x, p - 1, p) != 1) return false;  //费马小定理
    int y = p - 1, z;
    while (!(y & 1)) {  //二次探测
        y >>= 1;
        z = goodpow(x, y, p);
        if (z != 1 && z != p - 1) return false;
        if (z == p - 1) return true;
    }
    return true;
}

inline bool prime(int x) {
    if(x==46856248255981ll || x<2)
        return false;
//    if (x < 2) return 0;  // mille rabin判质数
    if (x == 2 || x == 3 || x == 5 || x == 7 || x == 43) return 1;
    return mr(2, x) && mr(3, x) && mr(5, x) && mr(7, x) && mr(43, x);
}
inline int rho(int p) {  //求出p的非平凡因子
    int x, y, z, c, g;
    int i, j;                 //先摆出来(z用来存(y-x)的乘积)
    while (1) {              //保证一定求出一个因子来
        y = x = rand() % p;  //随机初始化
        z = 1;
        c = rand() % p;                  //初始化
        i = 0, j = 1;                    //倍增初始化
        while (++i) {                    //开始玄学生成
            x = (lowpow(x, x, p) + c) % p;  //可能要用快速乘
            z = lowpow(z, Abs(y - x), p);  //我们将每一次的(y-x)都累乘起来
            if (x == y || !z)
                break;  //如果跑完了环就再换一组试试(注意当z=0时,继续下去是没意义的)
            if (!(i % 127) ||
                i == j) {  //我们不仅在等127次之后gcd我们还会倍增的来gcd
                g = gcd(z, p);
                if (g > 1) return g;
                if (i == j)
                    y = x, j <<= 1;  //维护倍增正确性,并判环(一箭双雕)
            }
        }
    }
}
unordered_map<int, int> um;
int max_prime_factor(int x) //求最大因子
{
    if (um.count(x))
        return um[x];
    int fac = rho(x);
    if (fac == 1)
        um[x] = x;
    else
        um[x] = max(max_prime_factor(fac), max_prime_factor(x / fac));
    return um[x];
}
int max_factor;
void fac(long long x) { //求最大质因子
    if (x <= max_factor || x < 2) return;
    if (prime(x)) {              // 如果x为质数
        max_factor = max(max_factor, x);  // 更新答案
        return;
    }
    long long p = x;
    while (p >= x) p = rho(x);  // 使用该算法
    while ((x % p) == 0) x /= p;
    fac(x), fac(p);  // 继续向下分解x和p
}
vector<int> factor;
void decompose(long long n) { // 将n分解为质因数相乘的形式
    srand((unsigned)time(NULL));
    max_factor = 0;
    fac(n);
    if(max_factor == n) { // 最大的质因数是自己
        factor.push_back(max_factor);
    }
    else {
        factor.push_back(max_factor);
        n /= max_factor;
        decompose(n);
    }
}

//inline void prho(int p) {   //不断的找他的质因子
//    if (p <= ans) return;  //最优性剪纸
//    if (prime(p)) {
//        ans = p;
//        return;
//    }
//    int pi = rho(p);  //我们一次必定能求的出一个因子,所以不用while
//    while (p % pi == 0) p /= pi;  //记得要除尽
//    return prho(pi), prho(p);     //分开继续分解质因数
//}
int vis[N];  //划掉合数
int prim[N]; //记录质数
int cnt; //质数个数
int max_pr[N];
void get_prim(int n) { //欧拉筛法-----O(N)
    vis[1]=1;
    for (int i = 2; i <= n; i++) {//越界中断
        if (!vis[i]) {
            prim[++cnt] = i;
            max_pr[i]=i;
        }
        for (int j = 1; i * prim[j] <= n; j++) {//乘以已经记录的数,越界中断,开筛
            vis[i * prim[j]] = 1;
            max_pr[i * prim[j]]=max(max_pr[i * prim[j]],max(prim[j],max_pr[i]));
            if (i % prim[j] == 0) break;//整除中断,保证被最小的质因子prim[j]划掉
        }
    }
}
void solve() {
//    srand((unsigned)time(NULL));
    int n;
    n = read();
    max_factor = 0;
    fac(n);
    int tmp=max_factor;
    int ans=1e18;
    if(tmp==n||n==1){
        cout<<-1<<endl;
        return;
    }
    get_prim(n);
    for(int i=n-tmp+1;i<n;i++){
        if(i-max_pr[i]+1>max_pr[i]){
            ans=min(ans,i-max_pr[i]+1);
        }
    }
    if(ans>n) cout<<-1<<endl;
    else cout<<ans<<endl;
}
signed main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
//    int t;
//    t=read();
//    while (t--)
    solve();
    return 0;
}
posted @ 2025-01-09 10:31  _LXYYYY  阅读(9)  评论(0)    收藏  举报