0
点赞
收藏
分享

微信扫一扫

Codeforces训练

龙驹书房 2022-04-06 阅读 49
算法c++

C. Circle of Monsters

题意:

首先我们要想, 如何用最少的子弹造成最大的伤害, 即尽可能的利用爆炸伤害, 所以从某个怪物开始, 每次射击的都是它后面未被炸死的怪物, 所以问题就变成了,从哪一个怪物开始射击, 所以我们枚举从每一个怪物开始,最开始我们要预处理出来利用上一个怪物的爆炸伤害, 我们还需要补几枪

#include<bits/stdc++.h>
#define x first
#define int long long 
#define ll long long 
#define y second
#define gg exit(0);
#define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define db printf("debug\n");
const int N = 5e5 + 10;
using namespace std;
typedef pair<ll, ll>PII;
int T;
long long a[N], b[N], n, c[N];

void solve()
{	
	cin >> n;

	for(int i = 1; i <= n; i ++ ) cin >> a[i] >> b[i];


	long long  sum = 0;
	for(int i = 1; i <= n; i ++ )
	{
		if(i == 1) c[i] = max((ll)0, a[i] - b[n]); 
		else c[i] = max((long long )0, a[i] - b[i - 1]);

		  sum += c[i];
	}
	long long  ans = 1e18;
	for(int i = 1; i <= n; i ++ )
		ans = min(ans, sum - c[i] + a[i]); //因为从这个怪物开始, 所以这个怪物受到的爆炸伤害不能计算在内

	cout << ans << '\n';
}
signed main()
{
	io;
	//T = 1;
	cin >> T;
	while(T -- )
	solve();
}

C. Ilya and Sticks

首先要面积最大,我们肯定会先用长的木棍拼在一起, 所以从大到小排序肯定没问题, 然后每四个一处理, 但是这里就出了点问题, 不一定是每四个一处理, 只要相邻两个能通过工具凑成一对, 就可以与其他对凑成矩形, 所以我们排序后,要每两个一处理, 然后放入数组, 最后一起计算面积

#include<bits/stdc++.h>
#define x first
#define ll long long 
#define y second
#define gg exit(0);
#define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define db printf("debug\n");
const int N = 5e5 + 10;
using namespace std;
typedef pair<ll, ll>PII;
int T;
ll n, a[N];
bool cmp(int a, int b)
{
	return a > b;
}
void solve()
{	
	 cin >> n;
	 vector<ll>b;
	 for(int i = 1; i <= n; i ++ )
	 	cin >> a[i];
	 sort(a + 1, a + 1 + n, cmp);
	 ll s = 0;
	 for(int i = 1; i <= n - 1; i ++)
	 	if(abs(a[i] - a[i + 1]) <= 1 )  //符合条件
	 		b.push_back(a[i + 1]), i ++;  //放入数组

	 for(int i = 0; i < (int)b.size() - 1; i += 2 )  //计算面积
	 	s += b[i] * b[i + 1];

	 cout << s << '\n';
}
signed main()
{
	io;
	T = 1;
	// cin >> T;
	while(T -- )
	solve();
}

C. New Year Book Reading

题意:

首先我们要确定每本书的初始位置, 我们不难知道, 通过一定的操作之后, 不论你书怎么放, 他的位置一定是固定的, 因为每次我们都要把那本书放到顶部, 所以当每本书都被放到顶部后, 他的位置就已经固定了, 与初始位置无关, 但是在每本书第一次本拿时, 与初始位置有关, 所以我们要根据每本书第一次本拿的位置, 确定每本书的初始位置
确定完初始位置后, 然后模拟即可

#include<bits/stdc++.h>
#define x first
#define ll long long 
#define y second
#define gg exit(0);
#define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define db printf("debug\n");
const int N = 5e5 + 10;
using namespace std;
typedef pair<ll, ll>PII;
int T;
ll n, w[N], b[N], m;
stack<int>s;
vector<int>a, c;
bool st[N];
void solve()
{	

	cin >> n >> m;

	for(int i = 1; i <= n; i ++ ) cin >> w[i];

	for(int i = 1; i <= m; i ++ ) cin >> b[i];

	for(int i = 1; i <= m; i ++ )
		if(!st[b[i]])  //这本书第一次出现
		{
			a.push_back(b[i]);
			st[b[i]] = true;
		}

	for(int i = (int)a.size() - 1; i >= 0; i -- ) s.push(a[i]);  //初始位置

	int sum = 0;
	for(int i = 1; i <= m; i ++ )
	{
		while(s.top() != b[i])  //将需要看的书的上面的书,全部取出, 并放入c数组,以便于后面再放回
		{
			sum += w[s.top()];  //计算答案
			c.push_back(s.top());
			s.pop();
		}
		s.pop();
		for(int i = (int)c.size() - 1; i >= 0; i -- ) s.push(c[i]);
		s.push(b[i]);   //别忘记把要看的这本书放在顶部
		c.clear(); //清空
	}
	cout << sum << '\n';
}
signed main()
{
	io;
	T = 1;
	// cin >> T;
	while(T -- )
	solve();
}

C. New Year and Rating

首先我们要确定初始分数, 只要确定了初始分数, 对于最终分数模拟即可求出, 但是如何确定最大的初始分数呢? 首先我们可以用两个变量表示初始分数的上下界, 如果下界大于上界就无解, 如果上界为正无穷, 说明最高分无上限, 然后通过每一次比赛, 可以确定上下界, 如果我下一场参加的是 B B B 组的比赛, 说明我这场比赛打完后我的得分的下界一定是小于等于1899的, 所以我们可以得到 r + c [ i ] < = 1899 r + c[i] <= 1899 r+c[i]<=1899 , 如果下一场参加的是 A A A 组的比赛, 那么我们打完这场比赛后一定是大于 1900 1900 1900 的, l + c [ i ] > = 1900 l + c[i] >= 1900 l+c[i]>=1900,这样我们就可以通过每一场比赛确定上下界了, 还要注意, 当第一场是A组比赛时, 我们需要把下界赋值为 1900 1900 1900, 否则赋值上界为 1899 1899 1899

#include<bits/stdc++.h>
#define x first
#define ll long long 
#define y second
#define gg exit(0);
#define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define db printf("debug\n");
const int N = 5e5 + 10;
using namespace std;
typedef pair<ll, ll>PII;
int T;
int n, c[N], d[N];
void solve()
{	
	cin >> n;

	for(int i = 1; i <= n; i ++ ) cin >> c[i], c[i] += c[i - 1], cin >> d[i];


	int l = -1e9, r = 1e9;
	if(d[1] == 1)
		   l = 1900;
	else
		r = 1899;
	for(int i = 1; i < n; i ++ )
		if(d[i + 1] == 1)
			l = max(l, 1900 - c[i]);  //更新下界
		else r = min(r, 1899 - c[i]);  //更新上界

	if(l > r) cout << "Impossible\n";
	else if(r == 1e9 ) cout << "Infinity\n";
	else cout << r + c[n] << '\n';
}

signed main()
{
	io;
	T = 1;
	// cin >> T;
	while(T -- )
	solve();
}

C. Anton and Fairy Tale

分析: 如果 n < = m n <= m n<=m, 那么当 i = n i = n i=n 时, 谷仓就变空了, 如果当 n > m n > m n>m时, 在 1 1 1 ~ m m m, 谷仓的谷子是不会变的, 然后从第 m + 1 m + 1 m+1 天开始, 谷仓的谷子每天减少1,2,3,4,5…,
所以我们可以推出 n - m <= (1 + x) * x / 2, 这里 n − m n - m nm 是因为每天麻雀吃的是 m + x m + x m+x, (这里 m + x m + x m+x 是指的第 m + x m + x m+x 天, 所以我们二分找到答案即可)

#include<bits/stdc++.h>
#define x first
#define int long long 
#define y second
#define gg exit(0);
#define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define db printf("debug\n");
const int N = 5e5 + 10;
using namespace std;
int T;
int n, m;
void solve()
{	
	cin >> n >> m;

	if(n <= m)
	cout << n << '\n';
	else 
	{
		int l = 0, r = 2e9; //左右边界 
		while(l < r)  //二分
		{
			int mid = (l + r) / 2;
			if((mid * (mid + 1)) / 2 >= (n - m)) r = mid;
			else l = mid + 1;
		}
		cout << l + m << '\n';
	}
}	
signed main()
{
	io;
	T = 1;
	// cin >> T;
	while(T -- )
	solve();
}

C. New Year and Permutation

对于这题, n n n 很大, 所以我们要计算贡献, 首先我们需要找到合法区间的数量,设合法区间的长度为 l e n len len, 那么从 1 1 1 ~ n − l e n + 1 n-len +1 nlen+1, 一共有 n − l e n + 1 n - len + 1 nlen+1 个, 然后内部顺序有 ! l e n !len !len 种, 外部有 ! ( n − l e n ) !(n - len) !(nlen) 种, 所以我们枚举长度, 答案就出来了
a n s = ∑ i = 1 n ( n − i + 1 ) × ! i × ! ( n − i ) ans = \sum_{i=1}^n(n - i + 1) × ! i × !(n - i) ans=i=1n(ni+1)×!i×!(ni)

#include<bits/stdc++.h>
#define x first
#define int long long 
#define y second
#define gg exit(0);
#define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define db printf("debug\n");
const int N = 5e5 + 10;
using namespace std;
int T;
int n, m;
int fac[N];
void solve()
{	
	cin >> n >> m;

	fac[0] = 1;
	fac[1] = 1;
	for(int i = 2; i <= n; i ++ ) fac[i] = fac[i - 1] * i % m;  //预处理阶乘

	int res = 0;
	for(int i = 1; i <= n; i ++ )  //一定要记得多取模, 不然爆longlong了
		res = ((res + ((((n - i + 1) * (n - i + 1) % m) * fac[i] % m )* fac[n - i]) % m ) % m);
	cout << res % m << '\n';
}	
signed main()
{
	io;
	T = 1;
	// cin >> T;
	while(T -- )
	solve();
}

D. Vupsen, Pupsen and 0

分析: 当 n n n 为偶数时, 两两配对即可, 例如 一个数为 a a a, 另一个数为 b b b, 则 b b b 数组为 − b -b b, a a a, 当 n n n 为奇数时, 我们只要处理掉前 3 3 3 个数, 剩下的就和偶数的情况一样了, 我们可以把三个数中的两个数看作一个整体, 然后当做两个数处理, 前提是这两个数的和不为 0 0 0, 例如,这三个数分别为 a , b , c a, b, c a,b,c, 我们可以是 a + b , c a + b, c a+b,c, 或者 a + c , b a + c, b a+c,b, 或者是 b + c , a b + c, a b+c,a, 其对应的 b b b 数组是 − c , − c , a + b -c, -c, a + b c,c,a+b, 或者 − b , − b , a + c -b, -b, a + c b,b,a+c, 或者是 − a , − a , b + c -a, -a, b + c a,a,b+c, 这三种情况并不是全都存在的, 要判断是否为 0 0 0,

#include<bits/stdc++.h>
#define x first
#define int long long 
#define y second
#define gg exit(0);
#define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define db printf("debug\n");
const int N = 5e5 + 10;
using namespace std;
int T;
int n, m;
int a[N], b[N];
void solve()
{	
	cin >> n;

	for(int i = 1; i <= n; i ++ ) cin >> a[i];


	if(!(n & 1))  //偶数情况
	{
		for(int i = 1; i <= n; i ++ )  
		{
			if(i % 2) cout << -1 * a[i + 1] << " ";
			else cout << a[i - 1] << " ";
		}
	}
	else
	{
		int x = a[1], y = a[2], z = a[3];  //处理前三个数
		if(x + z != 0)  
			cout << -1 * y << " " << x + z << " " << -1 * y << ' ';
		else if(x + y != 0)
			cout << -1 * z << " " << -1 * z << " " << x + y << ' ';
		else cout << y + z << " " << -1 * x << " " << -1 * x << ' ';

		for(int i = 4; i <= n; i ++ )
		{
			if(!(i % 2)) cout << -1 * a[i + 1] << " ";
			else cout << a[i - 1] << " ";
		}
	}
	cout << '\n';
}	
signed main()
{
	io;
	// T = 1;
	cin >> T;
	while(T -- )
	solve();
}
举报

相关推荐

0 条评论