1. 程式人生 > 實用技巧 >Educational Codeforces Round 92 (Rated for Div. 2) A-F

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