AtCoder Beginner Contest 254

C - K Swap

题意:给定一个整数序列,长度为n。每个数 a i a_i ai能与 a i + k a_{i + k} ai+k交换位置,是否能将该序列变换为升序。

思路:该序列可分为k个子序列:

  • a 0 , a 0 + k , a 0 + 2 k , . . . , a_0,a_{0+k}, a_{0+2k}, ... , a0,a0+k,a0+2k,...,
  • a 1 , a 1 + k , a 1 + 2 k , . . . , a_1,a_{1+k}, a_{1+2k}, ... , a1,a1+k,a1+2k,...,
  • a k − 1 , a k − 1 + k , a l − 1 + 2 k , . . . , a_k-1,a_{k-1+k}, a_{l-1+2k}, ... , ak1,ak1+k,al1+2k,...,

将这k个序列内部排序,放回原序列,判断原序列是否为升序。

Code

// Problem: C - K Swap
// Contest: AtCoder - AtCoder Beginner Contest 254
// URL: https://atcoder.jp/contests/abc254/tasks/abc254_c
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

/*
author: A Fei
*/ 
#include <bits/stdc++.h>

#define x first
#define y second
#define pi acos(-1) 
#define endl '\n'
#define ios ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define mem(x, a) memset(x, a, sizeof x)
#define pb(x) push_back(x)
#define rep(i, l, r) for(int i = l; i <= (r); ++ i)
#define per(i, r, l) for(int i = r; i >= (l); -- i)

using namespace std;
typedef long long LL;
typedef double DB;
typedef pair<int, int> PII;
typedef pair<int, double> PID;
typedef pair<double, double> PDD;
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1};
const int INF = 0x3f3f3f3f;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
const int N = 2e5 + 10;
int n, k;

int main()
{
	ios;
    cin >> n >> k;
    vector<int> a(n);
    
    rep(i, 0, n - 1) cin >> a[i];
    
    vector<int> c(n);
    rep(i, 0, k - 1)
    {
    	vector<int> b;
    	for(int j = i; j < n; j += k)	b.pb(a[j]);
    	sort(b.begin(), b.end());
    	for(int j = 0; j < b.size(); j ++)	c[i + j * k] = b[j];
    }
    
    // for(auto x : c) cout << x << ' ';
    // cout << endl;
    if(is_sorted(c.begin(), c.end())) cout << "Yes\n";
    else cout << "No\n"; 
    
    
    return 0;
}

D - Together Square

题意:找出有多少对儿: i , j i, j i,j,使得 i ∗ j i * j ij为平方数。( 1 < = i , j < = n 1 <= i, j <= n 1<=i,j<=n

思路:
可以考虑每个数都可分解质因子变为:
设 N 分 解 质 因 子 为 : N = p 1 a 1 ∗ p 2 a 2 ∗ ⋯ ∗ p n a n 其 中 p 1 , p 2 , ⋯   , p n 为 N 的 质 因 子 则 N 的 约 数 个 数 为 : f ( N ) = ( a 1 + 1 ) ∗ ( a 2 + 1 ) ∗ ⋯ ∗ ( a n + 1 ) 设N分解质因子为: \\N = p_1^{a_1} * p_2^{a_2} *\cdots*p_n^{a_n}\\其中p_1,p_2,\cdots,p_n为N的质因子\\ 则N的约数个数为:f(N) = (a_1 + 1) * (a_2 + 1) * \cdots* (a_n + 1) NN=p1a1p2a2pnanp1,p2,,pnNNf(N)=(a1+1)(a2+1)(an+1)
将该数中奇数个的质因子(记为 X i X_i Xi)拿出来计数(记为 C i C_i Ci)。


6: 2 1 ∗ 3 1 2^1 * 3^1 2131 --> 2 ∗ 3 = 6 2 * 3 = 6 23=6
24: 2 3 ∗ 3 1 2^3 * 3^1 2331 --> 2 ∗ 3 = 6 2 * 3 = 6 23=6
6 ∗ 24 = 144 = 1 2 2 6 * 24 = 144 = 12 ^ 2 624=144=122
所以当 i , j i, j i,j X X X相同时,说明 i ∗ j i * j ij的质因子个数都是偶数,即 i ∗ j i * j ij 为平方数。

答案为: C 1 2 + C 2 2 + . . . + C i 2 C_1^2 + C_2^2 + ... + C_i^2 C12+C22+...+Ci2

Code:

// Problem: D - Together Square
// Contest: AtCoder - AtCoder Beginner Contest 254
// URL: https://atcoder.jp/contests/abc254/tasks/abc254_d
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

/*
author: A Fei
*/ 
#include <bits/stdc++.h>

#define x first
#define y second
#define pi acos(-1) 
#define endl '\n'
#define ios ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define mem(x, a) memset(x, a, sizeof x)
#define pb(x) push_back(x)
#define rep(i, l, r) for(int i = l; i <= (r); ++ i)
#define per(i, r, l) for(int i = r; i >= (l); -- i)

using namespace std;
typedef long long LL;
typedef double DB;
typedef pair<int, int> PII;
typedef pair<int, double> PID;
typedef pair<double, double> PDD;
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1};
const int INF = 0x3f3f3f3f;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

int fun(int n)
{
	int res = 1;
	// i <= n / i -- why?:
	// 最多只会存在一个质因子 > sqrt(n), 两个的话 相乘 > n.
	// 当我们一直除最后n!=1,此时n就是那个大于sqrt(n)的质因子
	for(int i = 2; i <= n / i; i ++)
		if(n % i == 0)
		{
			int cnt = 0;
			while(n % i == 0) n /= i, cnt ++;
			if(cnt % 2) res *= i; 
		}
	if(n != 1) res *= n;
	return res;
}

int main()
{
	ios;
    int n;
    cin >> n;
    
    map<int, int> mp;
    rep(i, 1, n)
    {
    	int res = fun(i);
    	mp[res] ++;
    }
    
    LL ans = 0;
    for(auto x : mp) ans += x.y * x.y;
    cout << ans << endl;
    
    return 0;
}


E - Small d and k

题意:给定一个无向图, Q Q Q次询问。
每次询问:一个点走 K K K次,能到达所有边的权值和

思路: 简单BFS or DFS
错因: 数组开小了…
至少开: 2 ( 双 向 边 ) ∗ M = 3 ∗ N 2(双向边) * M = 3*N 2()M=3N在这里插入图片描述

Code

// Problem: E - Small d and k
// Contest: AtCoder - AtCoder Beginner Contest 254
// URL: https://atcoder.jp/contests/abc254/tasks/abc254_e
// Memory Limit: 1024 MB
// Time Limit: 3500 ms
// 
// Powered by CP Editor (https://cpeditor.org)

/*
author: A Fei
*/ 
#include <bits/stdc++.h>

#define x first
#define y second
#define pi acos(-1) 
#define endl '\n'
#define ios ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define mem(x, a) memset(x, a, sizeof x)
#define pb(x) push_back(x)
#define rep(i, l, r) for(int i = l; i <= (r); ++ i)
#define per(i, r, l) for(int i = r; i >= (l); -- i)

using namespace std;
typedef long long LL;
typedef double DB;
typedef pair<int, int> PII;
typedef pair<int, double> PID;
typedef pair<double, double> PDD;
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1};
const int INF = 0x3f3f3f3f;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
const int N = 6e5 + 10, M = 2 * N;
int h[N], ne[M], e[M], idx;
bool st[N];
int n, m;

void add(int a, int b)
{
	ne[idx] = h[a], e[idx] = b, h[a] = idx ++;
}

LL bfs(int x, int k)
{
	mem(st, false);
	queue<PII> q;
	q.push({x, 0});
	LL sum = 0;
	st[x] = true;
	
	while(q.size())
	{
		PII t = q.front();
		q.pop();
		
		int x = t.x, y = t.y;
		// depth ++;
		if(y <= k) sum += x;
		
		for(int i = h[x]; ~i; i = ne[i])
		{
			int j = e[i];
			
			if(!st[j] && y + 1 <= k) q.push({j, y + 1}), st[j] = true;
		}
	}
	return sum;
}

int main()
{
	ios;
	
    mem(h, -1);
    cin >> n >> m;
    
    while(m --)
    {
    	int a, b;
    	cin >> a >> b;
    	add(a, b), add(b, a);
    }
    
    int q, x, k;
    cin >> q;
    
    while(q --)
    {
    	cin >> x >> k;
    	// cout << x << k << endl;
    	cout << bfs(x, k) << endl;
    }
    
    
    return 0;
}


F - Rectangle GCD

题意:给定两个序列:
A 1 , A 2 , A 3 , . . . , A n A_1,A_2,A_3, ... , A_n A1,A2,A3,...,An
B 1 , B 2 , B 3 , . . . , B n B_1,B_2,B_3, ... , B_n B1,B2,B3,...,Bn
给两个坐标: ( a , b ) , ( c , d ) (a, b),(c, d) (a,b),(c,d),分别为矩阵左上角和右下角( 矩 阵 : C i , j = A i + B j 矩阵:C_{i,j} = A_i + B_j Ci,j=Ai+Bj),询问该范围内矩阵的 G C D GCD GCD

思路:
首先一个序列: G C D ( a 1 , a 2 , . . . , a n ) GCD(a_1, a_2,...,a_n) GCDa1,a2,...,an = G C D ( a 1 , a 2 − a 1 , . . . , a n − a n − 1 ) GCD(a_1, a_2 - a_1,...,a_n - a_{n-1}) GCDa1,a2a1,...,anan1
即:原序列的最大公约数 = 差分序列的最大公约数。

考虑矩阵任一行的数值:
A i + B j , A i + B j + 1 , A i + B j + 2 , A i + B j + 3 A_i+B_j,A_i+B_{j+1},A_i+B_{j+2},A_i+B_{j+3} Ai+Bj,Ai+Bj+1,Ai+Bj+2,Ai+Bj+3
做差分变为:
A i + B j , B j + 1 − B j , B j + 2 − B j + 1 , B j + 3 − B j + 2 A_i+B_j,B_{j+1} - B_{j},B_{j+2} - B_{j+1},B_{j+3} - B_{j + 2} Ai+Bj,Bj+1Bj,Bj+2Bj+1,Bj+3Bj+2
可以发现我们消去了: A i A_i Ai
对于查询的矩阵:
黄色部分的 G C D GCD GCD为: B 的 差 分 序 列 [ b + 1 , d ] B的差分序列[b+1,d] B[b+1,d] g c d 1 gcd_1 gcd1.
在这里插入图片描述
左边蓝色 G C D GCD GCD同理为: A 的 差 分 序 列 [ a + 1 , c ] A的差分序列[a+1,c] A[a+1,c] g c d 2 gcd_2 gcd2.
综上矩阵的 g c d gcd gcd为: G C D ( g c d 1 , g c d 2 , A a + B b − 空 白 快 ) GCD(gcd_1,gcd_2,A_a+B_b-空白快) GCD(gcd1,gcd2,Aa+Bb)

故可以用两个线段树维护两个序列的差分序列 g c d gcd gcd

Code:

// Problem: F - Rectangle GCD
// Contest: AtCoder - AtCoder Beginner Contest 254
// URL: https://atcoder.jp/contests/abc254/tasks/abc254_f
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

/*
author: A Fei
*/ 
#include <bits/stdc++.h>

#define x first
#define y second
#define pi acos(-1) 
#define endl '\n'
#define ios ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define mem(x, a) memset(x, a, sizeof x)
#define pb(x) push_back(x)
#define rep(i, l, r) for(int i = l; i <= (r); ++ i)
#define per(i, r, l) for(int i = r; i >= (l); -- i)

using namespace std;
typedef long long LL;
typedef double DB;
typedef pair<int, int> PII;
typedef pair<int, double> PID;
typedef pair<double, double> PDD;
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1};
const int INF = 0x3f3f3f3f;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
const int N = 2e5 + 10;

struct Node
{
	int l, r;
	int gcdd;
}tr_a[4 * N], tr_b[4 * N];

int n, Q;
int a[N], b[N], da[N], db[N];

int gcd(int a, int b)
{
	return b ? gcd(b, a % b) : a;
}

void pushup(Node tr[], int u)
{
	int l = u << 1, r = u << 1 | 1;
	tr[u].gcdd = gcd(tr[l].gcdd, tr[r].gcdd);
}

void build(Node tr[], int t[], int u, int l, int r)
{
	tr[u] = {l, r};
	if(l == r)
	{
		tr[u] = {l, l, t[l]};
		// cout << l << ' ' << r << ' ' << t[l] << endl;
		return ;
	}
	
	int mid = l + r >> 1;
	build(tr, t, u << 1, l, mid), build(tr, t, u << 1 | 1, mid + 1, r);
	pushup(tr, u);
}

Node query(Node tr[], int u, int l, int r)
{
	if(l > r) return {0, 0, 0};
	if(l <= tr[u].l && tr[u].r <= r) return tr[u];
	
	int mid = tr[u].l + tr[u].r >> 1;
	if(r <= mid) return query(tr, u << 1, l, r);
	else if(l > mid) return query(tr, u << 1 | 1, l, r);
	else 
	{
		Node left, right, res;
		left = query(tr, u << 1, l, r);
		right = query(tr, u << 1 | 1, l, r);
		res.gcdd = gcd(left.gcdd, right.gcdd);
		
		return res;
	} 
}

int main()
{
    ios;
    cin >> n >> Q;
    rep(i, 1, n) cin >> a[i];
    rep(i, 1, n) cin >> b[i];
    
    rep(i, 1, n) da[i] = a[i] - a[i - 1];
    rep(i, 1, n) db[i] = b[i] - b[i - 1];
    
	// rep(i, 1, n) cout << da[i] << ' ';
	// cout << endl;
	// rep(i, 1, n) cout << db[i] << ' ';
	// cout << endl;
	
    build(tr_a, da, 1, 1, n);
    build(tr_b, db, 1, 1, n);
    
    while(Q --)
    {
    	int r1, r2, c1, c2;
    	cin >> r1 >> r2 >> c1 >> c2;
    	
    	int g1 = query(tr_b, 1, c1 + 1, c2).gcdd;
    	int g2 = gcd(a[r1] + b[c1], query(tr_a, 1, r1 + 1, r2).gcdd);
    	cout << abs(gcd(g1, g2)) << endl;
    	// cout << a[r1] + b[c1] << ' ' << g1 << ' ' << g2 << endl;
    }
    
    
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值