Educational Codeforces Round 92 (Rated for Div. 2) A-F

数学和细节题十分不行的我,这场被打懵了。wa到自闭。


A
因为对两个数字求\(lcm\),至少需要小的数字乘以二。所以我们针对每个区间端点,乘以二,判断是否在内即可。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>
#include<cstdio>
#include <iomanip>
#pragma GCC optimize(2)
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
	char ch = getchar(); ll x = 0, f = 1;
	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;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
int T;
int l, r;
int main()
{
	T = read();
	while (T--)
	{
		l = read(), r = read();
		if (r < 2 * l) { printf("%d %d\n", -1 ,-1); }
		else {
			printf("%d %d\n", l, 2 * l);
		}
	}
	return 0;
}

B
由题意,一共可以走k步,每次回头只能走一步,那么我们可以发现,每一次回头一共就有了2次步数的减少(去+回),再加上题目按时回头走的次数不多于五次,所以我们枚举回头次数。
针对一共\(i\)次回头,我们最远能走到\(k-2*i。\)
我们只需要找到最大的\(a[i]+a[i+1]\),使得这个循环走\(i\)次即可。
其次,针对端点,可以考虑成从端点到端点+1,\(a[n]+a[n+1]\),这个循环走\(i\)次。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>
#include<cstdio>
#include <iomanip>
#pragma GCC optimize(2)
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
	char ch = getchar(); ll x = 0, f = 1;
	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;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
const int N = 1e5 + 10;
int T, n, k, z;
int a[N];
int main()
{
	T = read();
	while (T--)
	{
		n = read(), k = read(), z = read();
		upd(i, 1, n)a[i] = read();
		int ans = 0;
		upd(j, 0, z)
		{
			int len = k - 2 * j + 1;
			int mx = 0;
			int sum = 0;
			upd(i, 1, len)
			{
				mx = max(mx, a[i] + a[i + 1]);
				sum += a[i];
			}
			//sum += a[len];
			ans = max(ans, sum + j * mx);
		}
		printf("%d\n", ans);
	}
}

C
依题意,最后剩下的字符串一定形如\(abababab\)且长度是偶数。
所以暴力枚举我们剩余的两个数字即可。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>
#include<cstdio>
#include <iomanip>
#pragma GCC optimize(2)
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
	char ch = getchar(); ll x = 0, f = 1;
	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;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
const int N = 2e5 + 10;
int T, n;
char s[N];
int num[2];
int main()
{
	T = read();
	while (T--)
	{
		scanf("%s", s + 1);
		n = strlen(s + 1);
		int ans = INF;
		upd(a, 0, 9)
		{
			upd(b, 0, 9)
			{
				num[0] = a, num[1] = b;
				int now = 0;
				int sum = 0;
				upd(i, 1, n)
				{
					if (num[now] != s[i]-'0')sum++;
					else {
						now ^= 1;
					}
				}
				if (now == 1) {
					if (a != b)sum++;
				}
				ans = min(ans, sum);
			}
		}
		printf("%d\n", ans);
	}
	return 0;
}

D
分为两个情况,第一个相交,第二个是不相交。
相交的话,先判断相交的长度是否大于\(k\),小于了直接输出0。大于的话,接着判断。我们可以发现,对于一组木板,我们将他扩展\(L=min(a_l,b_l)\),\(R=max(a_r,b_r)\),是最优秀的。因为这样可以节省费用,同样是长度\(R-L\),分别扩展两个木板利用了自己的长度部分,使得费用是最少的。所以我们计算长度\(R-L\)\(n*(R-L)\),判断与k的关系,不行的话利用两倍费用暴力扩展即可。
当不相交,首先扩展木板到相同的长度,然后判断他的\(k\)的关系,如果\(k\)更小的话,我们需要判断费用是否更加优秀。
\(a_l,a_r,b_l,b_r\),我们假定a木板是更靠左的木板。有\(a_r<b_l\),将\(a\)木板扩展到刚好和b相交,有\(dist=(b_l-a_r)\),将\(a\)继续向右扩展,最多可以产生\(len=b_r-b_l\)的长度,费用是\(dist+len\)。当\(k<dist\)的时候,如果扩展\(a\)木板,会产生\(dist+k\)>\(2*k\)的费用,所以不如我们直接暴力扩展已经处理好的等长木板。否则的话,先扩展\(a\)在扩展\(b\).

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>
#include<cstdio>
#include <iomanip>
#pragma GCC optimize(2)
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
	char ch = getchar(); ll x = 0, f = 1;
	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;
}
typedef pair<ll, ll> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
const int N = 2e5 + 10;
int T;
ll n, k;
pir a, b;
ll judge(pir x, pir y)
{
	return min(y.second, x.second) - max(x.first, y.first);
}
int main()
{
	T = read();
	while (T--)
	{
		n = read(), k = read();
		ll ans = 0;
		a.first = read(); a.second = read();
		b.first = read(), b.second = read();
		ll tp = judge(a, b);
		if(tp>=0)
		{ 
			if (tp*n >= k) {
				ans = 0;
			}
			else {
				k -= tp * n;
				int mod = (max(a.second, b.second) - min(a.first, b.first)) - tp;
				if (mod*n >= k)
				{
					ans += k;
				}
				else {
					ans += mod * n + (k - mod * n) * 2;
				}
			}
		}
		else {
			if (a.first > b.first)swap(a, b);
			int mx = max(a.second, b.second); int mn = min(a.first, b.first);
			int mod = (mx - a.second) + (a.first - mn) + (mx - b.second) + (b.first - mn);
			int len = mx - mn;
			int dist = max(b.first, a.second) - min(b.first, a.second);
			if (k <= len)ans += dist + k;
			else {
				int cnt = 0;
				upd(i, 1, n) {
					if (k >= len) {
						k -= len; ans += mod;
						cnt++;
					}
					else break;
				}
				{
					if (cnt == n) {
						ans += k * 2;
					}
					else {
						if (dist > k)ans += 2 * k;
						else ans += 2 * dist + (k - dist);
					}
				}
			}
		}
		printf("%lld\n", ans);
	}
	return 0;
}

E
由,第x个月第y天和第y个月第x天是相同的星期几,我们可以得到:
\((x-1)*d+y\mod w==0\),\((y-1)*d+x \mod w==0\),两式相减,就有:
\((x-y)*(d-1)\mod w==0\)因为\((d-1)\)是常数,将\(d-1\)除掉。就有:
\((x-y)\mod (w/gcd(w,(d-1))==0\),因为\(x<=d\&x<=m\)同理可得\(y\)
故题目化简成求,有多少对\((x,y)\)满足上式。枚举倍数\(w''\),即\(x-y==w'\),针对\(dm=min(d,m)\)而言,一共有\(\sum_{i=1}^{dm/w'}dm-w'*i\),用通项公式化简即可。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>m
#include<cstdio>
#include <iomanip>
#pragma GCC optimize(2)
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
	char ch = getchar(); ll x = 0, f = 1;
	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;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
int T;
ll m, d, w;
ll gcd(ll a, ll b)
{
	return a ? gcd(b%a, a) : b;
}
int main()
{
	T = read();
	while (T--)
	{
		m = read(), d = read(), w = read();
		ll md = min(m, d);
		ll w_ = w / gcd(w, d - 1);
		ll cnt = md / w_;
		ll ans = 0;      
		ans = md * cnt - w_ * (cnt*(cnt + 1) / 2);
		printf("%lld\n", ans);
	}
	return 0;
}

F
考虑一个二分图(依靠颜色分为两种),我们如果正向连边,即颜色=1的点,向所有满足题意的颜色=2的点连边,该题不容易找到解法。反过来,如果颜色=1的向所以形成bad的颜色=2的点连边,那么题目就变成找到最大独立集。由网络流可以知道,最大独立集=n-最大匹配。故现在我们需要找到一个匹配方式,是最大的。
常规匹配变数可能是\(n^2\),我们需要找到一个更优秀的方法。容易想到,利用扫描线的思想,我们把每一个线段抽象成两个点,起点和终点。现在开两个集合,表示颜色1,颜色2。针对每一个起点,我们添加他的终点进入集合,针对每一个终点,我们匹配另外一个集合中,最小的终点。可以容易的发现这样贪心的正确性。(利用multiset,不然会wa4,终点多个重合的情况)

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>
#include<cstdio>
#include <iomanip>
#pragma GCC optimize(2)
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
	char ch = getchar(); ll x = 0, f = 1;
	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;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
const int N = 2e5 + 10;
int L[N], R[N], t[N];
int n;
struct node {
	int a, b, c;
};
multiset<int>s[3];
vector<node>vec;
int main()
{
	n = read();
	upd(i, 1, n) {
		L[i] = read(), R[i] = read(), t[i] = read(); t[i]--;
	}
	upd(i, 1, n)
	{
		vec.push_back(node{ L[i],i,0 });
		vec.push_back(node{ R[i],i,1 });
	}
	sort(vec.begin(), vec.end(), [](node t1, node t2) {
		if (t1.a == t2.a)
		{
			return t1.c < t2.c;
		}
		else { return t1.a < t2.a; };
	});
	int pi = 0;
	for (auto k : vec)
	{
		int id = k.b;
		int col = t[id];
		if (k.c == 1)
		{
			if (s[col].find(R[id]) != s[col].end())
			{
				if (s[col^1].size()) {
					pi++; s[col ^ 1].erase(s[col ^ 1].begin());
				}
				s[col].erase(s[col].find(R[id]));
			}
		}
		else {
			s[col].insert(R[id]);
		}
	}
	cout << n - pi << endl;
	return 0;
}
posted @ 2020-08-07 17:52  LORDXX  阅读(105)  评论(0编辑  收藏  举报