Educational Codeforces Round 161 (Rated for Div. 2)A~E

A. Tricky Template

问能否构造一个匹配串能和a、b匹配却不能和c匹配。

如果a和b某一位置上字母相同且和c这一位置上字母不同的话一定能构造出来

还有如果a、b、c某一位置上字母都不同的话匹配串放c这一位置上的大写字母也一定能构造出来

#include
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define endl '\n'

using namespace std;

typedef long long ll;

void solve()
{
	int n;
	cin >> n;
	string a, b, c;
	cin >> a >> b >> c;
	
	int f = 0;
	for(int i = 0; i < n; i ++)
	{
		if(a[i] == b[i] && a[i] != c[i])
		{
			f = 1;
			break;
		}
		
		if(a[i] != b[i] && a[i] != c[i] && b[i] != c[i])
		{
			f = 1;
			break;
		}
	}
	
	if(f)cout << "YES" << endl;
	else cout << "NO" << endl;
}

int main()
{
	IOS
	int _;
	cin >> _;
	while(_ --)
	{
		solve();
	}
	
	return 0;
}

 B. Forming Triangles

组成三角形只有两种情况:

1.三条边等长

2.两条边等长,第三条边比另外两条边短

没有其他情况了

#include
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define endl '\n'

using namespace std;

typedef long long ll;

const int N = 300010;

int a[N];

ll C(ll A, ll B)
{
	if(A < B)return 0;
	
	if(B == 2)
	{
		ll res = A * (A - 1) / 2;
		return res;
	}
	
	ll res = A * (A - 1) * (A - 2) / 6;
	return res;
}

void solve()
{
	int n;
	cin >> n;
	for(int i = 0; i <= n; i ++)a[i] = 0;
	
	for(int i = 0; i < n; i ++)
	{
		int x;
		cin >> x;
		a[x] ++;
	}
	
	ll ans = 0, cnt = 0;
	for(int i = 0; i <= n; i ++)
	{
		ans += C(a[i], 3) + cnt * C(a[i], 2);
		cnt += a[i];
	}
	cout << ans << endl;
}

int main()
{
	IOS
	int _;
	cin >> _;
	while(_ --)
	{
		solve();
	}
	
	return 0;
}

C. Closest Cities

前缀和,只要计算每两个城市之前的往返费用即可

#include
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define endl '\n'

using namespace std;

typedef long long ll;

const int N = 100010;

int x[N];
int a[N], b[N];

void solve()
{
	int n;
	cin >> n;
	for(int i = 0; i <= n; i ++)a[i] = b[i] = 0;
	
	for(int i = 1; i <= n; i ++)cin >> x[i];
	a[1] = 1, b[n] = 1;
	for(int i = 2; i < n; i ++)//1 - n-1
	{
		if(x[i + 1] - x[i] < x[i] - x[i - 1])a[i] = 1;
		else a[i] = x[i + 1] - x[i];
	}
	for(int i = n - 1; i > 1; i --)//2 - n
	{
		if(x[i] - x[i - 1] < x[i + 1] - x[i])b[i] = 1;
		else b[i] = x[i] - x[i - 1];
	}
	
	for(int i = 1; i <= n; i ++)
	{
		a[i] += a[i - 1];
		b[i] += b[i - 1];
	}
	
	int Q;
	cin >> Q;
	while(Q --)
	{
		int l, r;
		cin >> l >> r;
		if(l < r)//[l, r-1]
		{
			cout << a[r - 1] - a[l - 1] << endl;
		}
		else//[r+1, l]
		{
			cout << b[l] - b[r] << endl;
		}
	}
}

int main()
{
	IOS
	int _;
	cin >> _;
	while(_ --)
	{
		solve();
	}
	
	return 0;
}

D. Berserk Monsters

不难想到最多会删n次,和建立链表

但难点在如何快速地实现删这n次,暴力做法在n方,明显不可取

但有一个性质是下一轮新删的点必然是由这一轮删的点影响的,根据这个性质和set的排序,可以把时间复杂度降到nlogn,可取

可以把每个点和它本轮收到的实际伤害存到set中,每一次取<0的点,然后再把这些点影响到的点更新一下即可

#include
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define endl '\n'

using namespace std;

typedef long long ll;
typedef pair PII;

const int N = 300010;

int n;
int a[N], d[N];
int l[N], r[N];
bool st[N];
set S;

int get(int x)
{
	return d[x] - a[l[x]] - a[r[x]];
}

void del(int x)
{
	if(l[x] && !st[l[x]])S.erase({get(l[x]), l[x]});//把左右更新一下,原来的存在的话就把原来的删了 
	if(r[x] && !st[r[x]])S.erase({get(r[x]), r[x]});
	l[r[x]] = l[x];
	r[l[x]] = r[x];
	if(l[x] && !st[l[x]])S.insert({get(l[x]), l[x]});
	if(r[x] && !st[r[x]])S.insert({get(r[x]), r[x]});
}

void solve()
{
	S.clear();
	cin >> n;
	for(int i = 1; i <= n; i ++)cin >> a[i];
	for(int i = 1; i <= n; i ++)cin >> d[i];
	for(int i = 1; i <= n; i ++)
	{
		l[i] = i - 1, r[i] = i + 1;
		st[i] = false;
	}
	r[n] = 0;
	//a[n + 1] = 0;
	
	for(int i = 1; i <= n; i ++)
	{
		S.insert({get(i), i});
	}
	
	for(int i = 1; i <= n; i ++)
	{
		vector res;
		while(!S.empty() && S.begin()->first < 0)
		{
			int t = S.begin()->second;
			res.push_back(t);
			S.erase(S.begin());
			st[t] = true;
		}
		for(auto x : res)
		{
			del(x);
		}
		cout << res.size() << ' ';
	}
	cout << endl;
}

int main()
{
	IOS
	int _;
	cin >> _;
	while(_ --)
	{
		solve();
	}
	
	return 0;
}

E. Increasing Subsequences

构造题,看到的时候觉得应该可以往二进制角度去想

不考虑空序列的话,[0]是有1个上升子序列,[0 1]有三个子序列,增加了2个,这2个是[1]自身的一个和将[0]的所有上升子序列接到[1]前面,总共有两个

[0 1 2]是7个,增加了4个,分别是[2]的1个和[0 1]的3个接到[2]前面新生成的3个

以此类推0 1 2 3 4.....,分别依次增加8个、16个、32个.....

如果在[0 1 2 3 4]后再加一个2的话,依旧是增加了4个,按照先递增再递减的顺序是不会对彼此产生影响的。

这样就符合了二进制的条件。

#include
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define endl '\n'

using namespace std;

typedef long long ll;

const int N = 210;

ll a[N];

void solve()
{
	ll x;
	cin >> x;
	x --;
	vector ans;
	for(int i = 0; ; i ++)
	{
		if(a[i] <= x && a[i + 1] > x)
		{
			for(int j = 0; j <= i; j ++)ans.push_back(j);
			x -= a[i];
			break;
		}
	}
	
	for(int i = 62; i >= 0; i --)
	{
		if(x >> i & 1)ans.push_back(i);
	}
	cout << ans.size() << endl;
	for(auto xx : ans)cout << xx << ' ';
	cout << endl;
}

int main()
{
	IOS
	
	a[0] = 1;
	int i = 1;
	for(i = 1; i <= 61; i ++)
	{
		a[i] = a[i - 1] * 2 + 1;
	}
	
	int _;
	cin >> _;
	while(_ --)
	{
		solve();
	}
	
	return 0;
}

你可能感兴趣的:(cf,c++,算法)