Codeforces Round 955 (Div. 2)(A~E)

题目地址

前言

打得不好A~C,D没想到gcd。这场还是比较板,但是写得不够快。继续努力吧。

我的题解可能思路不是最优的,可能有点蠢,欢迎大家指导。

A

“可能从来没有平手” 的逆否命题是 “一定有平手时刻”

判断 \([x_1,x_2]\)\([y_1,y_2]\) 是否有一个全包含另一个的关系,有这个关系就一定有平手时刻。

Talk is cheap.Show me the code.

#include<bits/stdc++.h>
using namespace std;
inline int read() {
    int x = 0, f = 1; char ch = getchar();
    while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); }
    return x * f;
}
void solve() {
	int x1 = read(), y1 = read();
	int x2 = read(), y2 = read();
	if((x1<=y1&&y2<=x2) || (y1<=x1&&x2<=y2)) puts("NO");
	else puts("YES");
}
int main()
{
	int T = read();
	while(T--) solve();
	return 0;
}

B

模拟 \(x\) 加到 \(j*y\) 的过程,因为我不知道会模拟多少次,所以写了一个二分去寻找第一个 \(j*y>x\)。最后一定会进入一个循环节 \(1\) ~ \(y\),这里要处理一下。

Talk is cheap.Show me the code.

#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read() {
    int x = 0, f = 1; char ch = getchar();
    while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); }
    return x * f;
}
int x,y,k;
int find(int x) {
	int l = 0, r = 1e9, res = 0;
	while(l <= r) {
		int mid = (l + r) >> 1;
		if(mid*y > x) {
			res = mid;
			r = mid - 1;
		} else l = mid + 1;
	}
	return res*y;
}
void solve() {
	x = read(), y = read(), k = read();
	while(k>0) {
		int p = find(x);
		if(p-x <= k) {
			k -= p-x;
			while(p%y == 0) {
				p /= y;
			}
			x = p;
			if(x==1) {
				x += k%(y-1);
				k = 0;	
			}
		} else {
			x += k;
			k = 0;
		}
	}
	printf("%lld\n",x);
}
signed main()
{
	int T = read();
	while(T--) solve();
	return 0;
}
/*
1
998244353 2 998244353
*/

C

贪心。因为前面尽可能少取一定是最优的。所以设置一个当前指针 \(j\),往后取若干个使得 \(sum \ge L\),这时有可能 \(sum \ge R\),所以前面也丢弃若干个使得 \(sum \le R\),这时如果前面丢弃若干个不能满足条件,那么 \(j=j+1\)。如果满足了条件 \(L \le sum \le R\),则 \(j=k+1\)\(k\) 是往后取若干个后的下标)。重复上述过程。

这个过程往后取若干和往前取若干都是用二分,每次做一次过程 \(j\) 至少 \(+1\),因此时间复杂度 \(O(n \log n)\)

#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read() {
    int x = 0, f = 1; char ch = getchar();
    while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); }
    return x * f;
}
const int N = 1e5+7;
int n,L,R;
int a[N],s[N];
int S(int l,int r) {
	return s[r] - s[l-1];
}
void solve() {
	n = read(), L = read(), R = read();
	for(int i=1;i<=n;++i) a[i] = read();
	for(int i=1;i<=n;++i) {
		s[i] = s[i-1] + a[i];
	}
	int j = 1, ans = 0;
	while(j<=n) {
		int l = j, r = n, res = j;
		while(l <= r) {
			int mid = (l + r) >> 1;
			if(S(j, mid) >= L) {
				res = mid;
				r = mid - 1;
			} else l = mid + 1;
		}
		int k = res;
		l = j, r = k, res = j;
		while(l <= r) {
			int mid = (l + r) >> 1;
			if(S(mid, r) <= R) {
				res = mid;
				r = mid - 1;
			} else l = mid + 1;
		}
		int sum = S(res, k);
		if(L<=sum && sum<=R) {
			++ans;
			j = k + 1;
		} else {
			++j;
		}
	}
	printf("%lld\n",ans);
	
	for(int i=1;i<=n;++i) {
		a[i] = s[i] = 0;
	}
}
signed main()
{
	int T = read();
	while(T--) solve();
	return 0;
}
/*
1
9 7 9
2 10 5 1 3 7 6 2 3

1
5 10 15
5 7 7 9 1
*/

D

题目看起来很复杂,其实很多信息都没用。因为问的是总和能不能相等。记初始总和的差(绝对值)是 \(t\)。用一个二维前缀和处理一下所有 \(k*k\) 矩阵中 \(0/1\) 的差(绝对值) \(dt\) ,每个 \(dt\) 代表当它对应的 \(k*k\) 矩阵进行操作时,它能对 \(t\) 改变 \(i*dt\)\(i\) 是任意整数)

换言之,问题变为:给你 \(\{dt_i\}\)\(t\),问是否存在 \(\{x_i\}\), \(x_i \in \Z\) 使得 \(\sum dt_i*x_i = t\)(注意 \(x_i\) 可以为负数)

著名的裴蜀定理告诉我们,一个数集 \(\{a_i\}\) 可以通过加减组合出来的数集是 \(\{i*gcd(a_1,a_2,...,a_n), i \not = 0,i \in \Z\}\)。故解决该题。

纯纯板子啊呜呜呜www

Talk is cheap.Show me the code.

#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read() {
    int x = 0, f = 1; char ch = getchar();
    while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); }
    return x * f;
}
const int N = 507;
int n,m,k;
int a[N][N];
int s[N][N];
char g[N][N];
int get(int x1,int y1) {	//x,y为右上角的k*k矩阵 
	int x2 = x1+k-1, y2 = y1+k-1;
	return s[x2][y2] - s[x1-1][y2] - s[x2][y1-1] + s[x1-1][y1-1];
}
void solve() {
	n = read(), m = read(), k = read();
	for(int i=1;i<=n;++i) {
		for(int j=1;j<=m;++j) {
			a[i][j] = read();
		}
	}
	for(int i=1;i<=n;++i) {
		scanf("%s",g[i]+1);
	}
	vector<int> mou(2, 0);
	for(int i=1;i<=n;++i) {
		for(int j=1;j<=m;++j) {
			mou[g[i][j]-'0'] += a[i][j];
		}
	}
	for(int i=1;i<=n;++i) {
		for(int j=1;j<=m;++j) {
			s[i][j] = s[i-1][j] + s[i][j-1] - s[i-1][j-1] + (g[i][j]-'0');
		}
	}
	int d = 0;
	for(int i=1;i+k-1<=n;++i) {
		for(int j=1;j+k-1<=m;++j) {
			int y = get(i, j), x = k*k - y;
			if(abs(x-y) > 0) {
				d = (d ? __gcd(d, abs(x-y)) : abs(x-y));
			}
		}
	}
	if((d&&(abs(mou[0]-mou[1])%d==0)) || !(abs(mou[0]-mou[1]))) puts("YES");
	else puts("NO");
	
	for(int i=1;i<=n;++i) {
		for(int j=1;j<=m;++j) {
			a[i][j] = g[i][j] = s[i][j] = 0;
		}
	}
}
signed main()
{
	int T = read();
	while(T--) solve();
	return 0;
}
/*
1
3 3 2
2 1 1
1 1 2
1 5 4
010
101
010
*/

E

咕咕咕...待补

posted @ 2024-06-26 11:34  基地AI  阅读(12)  评论(0编辑  收藏  举报