Codeforces Round #510 (Div. 2)

Codeforces Round #510 (Div. 2)

可能我太就没参加比赛了..这次比赛思路出的蛮快的,但是emmmm代码能力下降了。

大概是...在洛谷刷的水题太多了TAT

目前简单把自己看的题目写出来,之后继续补题。

前三道题:第一、三题都是模拟,第二道我跑了个DFS,有空看一下题解的解法。

这里提前讲一下第二题我是DFS写完之后没考虑第一步就完成操作的...得到所有解法都是一步以上的..

A. Benches

题意:沙滩上有n个位置,且有n个人要来,问位置上最多的人的最大可能和最小可能

最大可能很简单,就是都往原来最多的位置走。

最小我是先把小于最大值的填满,填不满就是最大值,填的满就继续平均分,求最大

#include<string>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<map>
#include<vector>
#include<set>

#define FOR(a,b) for(register int i=a;i<=b;i++)
#define ULL unsigned long long
#define LL long long

using namespace std;
int main()
{
	int a[10000];
	int n,m;
	cin >> n>>m;
	int Mi,Mx;
	int sum = 0;
	FOR(1, n)
	{
		cin >> a[i];
		sum += a[i];
	}
	sort(a + 1, a + 1 + n);
	Mx = a[n] + m;
	int M = a[n];
	sum = -sum + M * n;
	
	if (sum >= m)Mi = M;
	else
	{
		if((m-sum)%n)
		Mi = M + (m - sum) / n + 1;
		else Mi = M + (m - sum) / n;
	}
	cout << Mi << " " << Mx << endl;
	return 0;
}

B. Vitamins

题意:有n个交易,给多少钱,还你ABC,问拿到ABC所有种类需要多少钱

DFS跑所有路径,如果接下来的点对你的ABC种类没有贡献就不跑。

PS:我已开始漏判断了一个交易就直接满足且最优的情况 FST了

#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<map>
#include<vector>
#include<set>

#define FOR(a,b) for(register int i=a;i<=b;i++)
#define ULL unsigned long long
#define LL long long
using namespace std;
int F[4];
struct node
{
	int p;
	char s[5];
}A[3000];
void cal(char s[])
{
	memset(F, 0, sizeof(F));
	int sum = 0;
	for (int i = 0; i < strlen(s); i++)
	{
		F[s[i] - 'A' + 1] = 1;
	}
}
int cmp(node a, node b)
{
	return a.p < b.p;
}

int H[10000000];
int cnt = 0;
int E[1010];
int flag = 1;

void dfs(int a, int b, int c, int sum, int n)
{
	if (a == 1 && b == 1 && c == 1)
	{
		H[++cnt] = sum;
		//		cout << sum << ":";
				//for (int i = 1; i <= n; i++)
					//cout << E[i] << " ";
				//cout << endl;
		return;
	}
	else
	{
		for (int i = 1; i <= n; i++)
		{
			if (!E[i])
			{
				flag = 0;
				cal(A[i].s);
				//	cout << F[1] << " " << F[2] << " " << F[3] <<  endl;
				//	cout << a << " " << b << " " << c << " " << endl;
				if (a == 0 && F[1])flag = 1;
				if (b == 0 && F[2])flag = 1;
				if (c == 0 && F[3])flag = 1;
				if (flag)
				{
					E[i] = 1;

					dfs(F[1] || a, F[2] || b, F[3] || c, A[i].p + sum, n);
					E[i] = 0;
				}
			}
		}
	}
}
int main()
{
	memset(E, 0, sizeof(E));
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> A[i].p;
		cin >> A[i].s;
		cal(A[i].s);
		if (F[1] && F[2] && F[3])
		{
			H[++cnt] = A[i].p;
		}
	}
	dfs(0, 0, 0, 0, n);
	if (cnt)
	{
		sort(H + 1, H + 1 + cnt);
		cout << H[1] << endl;
	}
	else cout << "-1" << endl;
	//return H[1];
}

C. Array Product

题意:两个操作:

A.把i,j变成一个,且a[i]消失,a[j]=a[i]*a[j]

B.直接删除一个元素,但只能使用一次

问怎么操作,使得操作到只剩下一个元素的时候值最大。

解法写在注释里了

#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<map>
#include<vector>
#include<set>
#include<cctype>

#define rep(a,b) for(register int i=a;i<=b;i++)
#define red(a,b) for(register int i=a;i>=b;i--)
#define ULL unsigned long long
#define LL long long
using namespace std;

inline int read();
inline double dbread();

vector<LL>vec0;
vector<LL>vecF;
vector<LL>vecA;

LL arr[200050];
int main()
{
	int n;
	LL MAX=10e11+7;
	int MI = -1;
	cin >> n;

	rep(1, n)
	{
		scanf_s("%I64d", &arr[i]);
		if (!arr[i])vec0.push_back(i);
		if (arr[i] < 0)
		{
			vecF.push_back(i);
			if (MAX > abs(arr[i]))
			{	
				MAX = -arr[i];
				MI = i;
		    }
		}
	}

	rep(1, n)
	{
		if (i != MI&&arr[i]!=0)
		{
			vecA.push_back(i);
		}
	}

	//特殊情况处理:最后为0的答案必须要留下0,不能清除。
	/*
	总体思想:
	非零数相乘为正,直接写出答案,消除0即可;
	为负,需要用一个0消去绝对值最小的负数或者自我消除。
	在之前把所有0消去即可。
	所以预处理判断答案是否为0,如果为0,即只有一个负数或者没有非零数。
	*/
	if (vecA.size() == 0)//只有一个负数也会导致没有元素
	{
		if(vec0.size()>1)
		rep(0, vec0.size()-1-1)
		{
			printf("1 %I64d %I64d\n", vec0[i], vec0[i + 1]);
		}
		if(MI!=-1)
		printf("1 %I64d %d\n",vec0[vec0.size()-1],MI);
	}
	else
	{
		if (vecF.size() % 2)
		{
			if (vec0.size() > 0)
				printf("1 %Id %I64d\n", MI, vec0[0]);
			else
				printf("2 %d\n", MI);
		}
		else if(MI!=-1) vecA.push_back(MI);
		//cout << vec0.size();
		if(vec0.size()>1)
		rep(0,vec0.size()-1 -1)
			printf("1 %I64d %I64d\n", vec0[i],vec0[i+1]);
		if(vec0.size()>0)
		printf("2 %I64d\n",vec0[vec0.size()-1 ]);
		if(vecA.size()>1)
		rep(0, vecA.size() - 1 - 1)
			printf("1 %I64d %I64d\n", vecA[i], vecA[i + 1]);
	}
	//system("pause");
	return 0;
}


D.Petya and Array

 题意:中途几天为了做这题还跑去看树状数组,等会做了才发现线段树也可以做QAQ.就是逆序对的一道变题,需要离散化的操作QAQ明明我之前研究过的。果然还是洛谷水题做多了。

sum[j]-sum[i-1]<k 

sum[j]<sum[i-1]+k

就是求逆序对,对于每加入一个sum[j],判断之前是否放入过比他大的sum[i-1]+k。

权值树状数组?

数据较大,离散化操作即可,因为数据总大小只有2*10e5

把数据离散化成:1 2 3 4 5 6  6 6 7 8这样子,利用权值线段树即可,我这里用的是树状数组

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<set> 
using namespace std;

int sum[200050*2];

int lowbit(int x)
{
	return x & (-x);
} //返回最小的值

void update(int pos, int val,int x)
{
	while (pos <= x)
	{
		sum[pos] += val;
		pos += lowbit(pos);
	}
}//维护的是前缀和 

int query(int pos)
{
	int s = 0;
	while (pos)
	{
		s += sum[pos];
		pos -= lowbit(pos);
	}
	return s;
}//就算是前面的更新,也只是把需要用到的更新了,求区间和的时候需要按1的位置加起来。 

struct node
{
	int id;
	long long w;
}arr[200050*2];

int B[200050*2];

int cmp(node a, node b)
{
	return a.w < b.w;
}

int main()
{
	int N;
	long long t;
	cin >> N >> t;
	int cnt1 = 0, cnt2 = 0;
	int d = 0;
	memset(arr, 0, sizeof(arr));
	for (int i = 1; i <= N; i++)
	{
		scanf("%lld", &arr[i].w);
		arr[i].w += arr[i - 1].w;
		arr[i].id = i;
	}
	for (int i = N + 1; i <= 2 * N; i++)
	{
		arr[i].w = arr[i - N - 1].w + t;
		arr[i].id = i;
	}
	sort(arr + 1, arr + 1 + 2*N, cmp);
	for (int i = 1; i <= 2 * N; i++)
	{
		if(arr[i].w!=arr[i-1].w)
		B[arr[i].id] = ++d;
		else B[arr[i].id] = d;
	//	cout << arr[i].w << " ";
	}
	//cout << endl;
	//cout << d << endl;
	long long ans = 0;
	for (int i = 1; i <= N; i++)
	{
		update(B[i+N], 1,d);
		//cout << B[i + N]<<endl;
		ans += query(d) - query(B[i]);
		//cout << B[i] << endl;
		//cout << ans << endl;
	}
	cout << ans << endl;
	
	return 0;
}

E. Vasya and Magic Matrix

题意:给定一个芯片,芯片可以往比自己所在位置权值低的位置走,走过去的贡献是曼哈顿距离的平方,如果能走,走的操作是随机发生的。求贡献的期望。

期望:正着推很难,从最终位置反向推就会简单些:

P(a[i])=\sum_{j=1}^{k}p(a[j])+(xj-xi)^2+(yj-yi)^2

继续化简即可。

P(a[i])=\sum_{j=1}^{k}(p(a[j])+xj^2+yj^2)-2xi\sum_{j=1}^{k}xj-2yi\sum_{j=1}^{k}yj+k*(xi^2+yi^2)

j为到达a[i]之前所在的位置,权值显然比a[i]的大,排序,递推即可。

#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<map>
#include<vector>
#include<set>
#include<cctype>

#define rep(a,b) for(register int i=a;i<=b;i++)
#define red(a,b) for(register int i=a;i>=b;i--)
#define ULL unsigned long long
#define LL long long
#define MOD 998244353

using namespace std;

int r, c;
LL dp[3000][3000];

struct node
{
	int x;
	int y;
	LL val;
}matrix[1000100];

LL quickpow(long long n, long long base) {
	long long res = 1;
	while (n) {
		if (n & 1) {
			res = res * base % MOD;
		}
		n >>= 1;
		base = base * base % MOD;
	}
	return res;
}//快速幂 

int inv(int a)
{
	return quickpow(MOD-2,a);
}

int check(int n,int m)
{
	for (int i = 1; i <= n * m; i++)
	{
		if (matrix[i].x == r && matrix[i].y == c)
		{
			return i;
		}
	}
}

int cmp(node a, node b)
{
	return a.val < b.val;
}
int main()
{
	int n, m;
	cin >> n >> m;
	int cnt = 0;
	memset(matrix, 0, sizeof(matrix));
	for(int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
		{
			scanf("%lld", &matrix[++cnt].val);
			matrix[cnt].x = i; matrix[cnt].y = j;
	//cout << matrix[i].val << endl;
		}
	}
	cin >> r >> c;
	sort(matrix + 1, matrix + 1 + n * m,cmp);
//	for (int i = 1; i <= n * m; i++)
	//	cout << matrix[i].val << endl;
	int res=check(n, m);
	
	LL totF = 0, totX = 0, totY = 0, tot = 0;
	LL anF = 0, ansX = 0, ansY = 0;
	LL ans = 0;
	//cout << res << endl;
	rep(1, res)
	{
		LL x = matrix[i].x, y = matrix[i].y;
        
		//cout << ans << endl;
		ans = (((x * x + y * y) % MOD*tot + anF -2 * x * ansX - 2 * y * ansY)%MOD + MOD) % MOD;
		ans = (ans*inv(tot)) % MOD;

		totF = (totF + ans + (x * x + y * y)) % MOD;
		totX = (totX + x) % MOD;
		totY = (totY + y) % MOD;
		if (matrix[i].val != matrix[i + 1].val)
		{
			anF =  totF % MOD;
			ansX = totX % MOD;
			ansY = totY % MOD;
			tot = i;
		}
	}
	printf("%I64d", ans);
	//system("pause");
}

F. Leaf Sets

题意:在树中有多少个区域,区域内任意两点距离<=k。

见代码注释

#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<map>
#include<vector>
#include<set>
#include<cctype>

#define rep(a,b) for(register int i=a;i<=b;i++)
#define red(a,b) for(register int i=a;i>=b;i--)
#define ULL unsigned long long
#define LL long long

using namespace std;

const int N = 10e6 + 100;

vector< int >vec[N];

/*
对于一棵树,从中间节点开始遍历//PS:便于dfs判断到底,
遍历所到的每一个子树,筛掉大的,
大的往上只会更大,更不符合条件,
小的留下来递归回去+1判断是否符合条件,
符合就留下来
继续上去,不符合又筛掉
每次只对儿子处理
*/

int ans = 0, k;

int dfs(int v, int p)
{
	if (vec[v].size() == 1)
	{
		return 0;
	}
	vector< int >val;
	for (auto u : vec[v])
	{
		if (u == p)continue;
		val.push_back(dfs(u, v) + 1);
	}
	sort(val.begin(), val.end());

	while (val.size() >= 2)
	{
		if (val.back() + val[val.size() - 2] <= k)
			break;
		ans++;
		val.pop_back();
	}
	return val.back();//子树最大距离:如果符合,一定是距子树底的最远距离也合格起码。
}

int main()
{
	int n;
	int a, b;
	cin >> n >> k;


	rep(1, n - 1)
	{
		scanf("%d%d", &a, &b);
		a--, b--;
		vec[a].push_back(b);
		vec[b].push_back(a);
	}
	rep(0, n - 1)
	{
		if (vec[i].size() > 1)
		{
			dfs(i, -1);
			break;
		}
	}
	cout << ans + 1 << endl;//加上初始留到最后的那一个val。
//	system("pause");
}

猜你喜欢

转载自blog.csdn.net/mxYlulu/article/details/82749868
今日推荐