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;
}

浙公网安备 33010602011771号