思维题训练
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) { //非递归求gcdint 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我们还会倍增的来gcdg = 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;elseum[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;
}