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

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


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

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
#include
#include 
#pragma GCC optimize(2)
#define up(i,a,b)  for(int i=a;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 i i次回头,我们最远能走到 k − 2 ∗ i 。 k-2*i。 k2i
我们只需要找到最大的 a [ i ] + a [ i + 1 ] a[i]+a[i+1] a[i]+a[i+1],使得这个循环走 i i i次即可。
其次,针对端点,可以考虑成从端点到端点+1, a [ n ] + a [ n + 1 ] a[n]+a[n+1] a[n]+a[n+1],这个循环走 i i i次。

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
#include
#include 
#pragma GCC optimize(2)
#define up(i,a,b)  for(int i=a;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
依题意,最后剩下的字符串一定形如 a b a b a b a b abababab abababab且长度是偶数。
所以暴力枚举我们剩余的两个数字即可。

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
#include
#include 
#pragma GCC optimize(2)
#define up(i,a,b)  for(int i=a;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 k k,小于了直接输出0。大于的话,接着判断。我们可以发现,对于一组木板,我们将他扩展 L = m i n ( a l , b l ) L=min(a_l,b_l) L=min(al,bl), R = m a x ( a r , b r ) R=max(a_r,b_r) R=max(ar,br),是最优秀的。因为这样可以节省费用,同样是长度 R − L R-L RL,分别扩展两个木板利用了自己的长度部分,使得费用是最少的。所以我们计算长度 R − L R-L RL n ∗ ( R − L ) n*(R-L) n(RL),判断与k的关系,不行的话利用两倍费用暴力扩展即可。
当不相交,首先扩展木板到相同的长度,然后判断他的 k k k的关系,如果 k k k更小的话,我们需要判断费用是否更加优秀。
a l , a r , b l , b r a_l,a_r,b_l,b_r al,ar,bl,br,我们假定a木板是更靠左的木板。有 a r < b l a_rar<bl,将 a a a木板扩展到刚好和b相交,有 d i s t = ( b l − a r ) dist=(b_l-a_r) dist=(blar),将 a a a继续向右扩展,最多可以产生 l e n = b r − b l len=b_r-b_l len=brbl的长度,费用是 d i s t + l e n dist+len dist+len。当 k < d i s t kk<dist的时候,如果扩展 a a a木板,会产生 d i s t + k dist+k dist+k> 2 ∗ k 2*k 2k的费用,所以不如我们直接暴力扩展已经处理好的等长木板。否则的话,先扩展 a a a在扩展 b b b.

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
#include
#include 
#pragma GCC optimize(2)
#define up(i,a,b)  for(int i=a;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 m o d    w = = 0 (x-1)*d+y\mod w==0 (x1)d+ymodw==0, ( y − 1 ) ∗ d + x m o d    w = = 0 (y-1)*d+x \mod w==0 (y1)d+xmodw==0,两式相减,就有:
( x − y ) ∗ ( d − 1 ) m o d    w = = 0 (x-y)*(d-1)\mod w==0 (xy)(d1)modw==0因为 ( d − 1 ) (d-1) (d1)是常数,将 d − 1 d-1 d1除掉。就有:
( x − y ) m o d    ( w / g c d ( w , ( d − 1 ) ) = = 0 (x-y)\mod (w/gcd(w,(d-1))==0 (xy)mod(w/gcd(w,(d1))==0,因为 x < = d & x < = m x<=d\&x<=m x<=d&x<=m同理可得 y y y
故题目化简成求,有多少对 ( x , y ) (x,y) (x,y)满足上式。枚举倍数 w ′ ′ w'' w,即 x − y = = w ′ x-y==w' xy==w,针对 d m = m i n ( d , m ) dm=min(d,m) dm=min(d,m)而言,一共有 ∑ i = 1 d m / w ′ d m − w ′ ∗ i \sum_{i=1}^{dm/w'}dm-w'*i i=1dm/wdmwi,用通项公式化简即可。

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#includem
#include
#include 
#pragma GCC optimize(2)
#define up(i,a,b)  for(int i=a;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 n^2 n2,我们需要找到一个更优秀的方法。容易想到,利用扫描线的思想,我们把每一个线段抽象成两个点,起点和终点。现在开两个集合,表示颜色1,颜色2。针对每一个起点,我们添加他的终点进入集合,针对每一个终点,我们匹配另外一个集合中,最小的终点。可以容易的发现这样贪心的正确性。(利用multiset,不然会wa4,终点多个重合的情况)

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
#include
#include 
#pragma GCC optimize(2)
#define up(i,a,b)  for(int i=a;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;
}

你可能感兴趣的:(数学,扫描线,模拟)