Educational Codeforces Round 1 A---E

Educational Codeforces Round 1

总结

涉及到计算几何—极角排序及简单线性DP
极角排序的确知识盲区。
VP的时候没出E题,很可惜, 不要被题目吓倒就好了。
尽力写就好了,反正赛后还要补题。

A. Tricky Sum

题意:

求1–n所有数字之和,仅有2的幂次方的数字为负数。

int main()
{
	int T;
	scanf("%d", &T);
	while(T --)
	{
		ll n;
		scanf("%lld", &n);
		ll sum = n * (1ll + n) / 2;
		ll temp = 1;
		while(1)
		{
			if(temp <= n)
			sum -= temp * 2ll;
			else break;
			temp *= 2ll;
		}
		printf("%lld\n", sum);
	}
	return 0;
}

B. Queries on a String

题意:

给定m个查询,每次查询给定l, r, k,将[l ,r]区间中的字符循环移动k次,最后一个移到首位,其他不变。求m次操纵后的字符串

思路:

观察范围,暴力即可

char last[maxn], ans[maxn];
int main()
{	
	scanf("%s", last + 1);
	int len = strlen(last + 1);
	for(int i = 1 ; i <= len ; i ++)
	ans[i] = last[i];
	int m;
	scanf("%d", &m);
	for(int i = 1 ; i <= m ; i ++)
	{
		int l, r, k;
		scanf("%d %d %d", &l, &r, &k);
		int temp = k % (r - l + 1);
		if(temp == 0) continue;
		int cur = l;
		for(int j = r - temp + 1; j <= r ; j ++)
		{
			ans[cur ++] = last[j];
		}
		for(int j = l ; j <= r - temp ; j ++)
		{
			ans[cur ++] = last[j];
		}
		for(int j = 1 ; j <= len ; j ++)
		last[j] = ans[j];
	}
	printf("%s\n", ans + 1);
	return 0;
}

C. Nearest vectors

题意:

给定n个坐标,求出原点和n个坐标形成了若干向量之间,夹角最小的两条向量的编号

思路:

经典的极角排序。(知识盲区)
atan2(y, x):返回(x,y)和x轴正半轴的夹角,返回值[-PI / 2, PI / 2]。
注意此函数存在误差,取long double
考虑两个向量之前的夹角为[0,PI],要么是两角之间的差值,要么是其补角,注意最小角和最大角还要再次比较

struct note{
	int id;
	double x;
	double y;
	long double d;
	bool operator < (const note &a) const
	{
		return d < a.d;
	}
}point[maxn];
int main()
{
	int n;
	scanf("%d", &n);
	for(int i = 1 ; i <= n ; i ++)
	{
		double x, y;
		scanf("%lf %lf", &x, &y);
		double d = atan2(y, x);
		point[i] = {i,x, y, d};
	}
	sort(point + 1, point + n + 1);
	long double minn = min(point[n].d - point[1].d, 2 * PI - (point[n].d - point[1].d));
	int res1 = point[1].id, res2 = point[n].id;
	for(int i = 1 ; i <= n ; i ++)
	{
		if(i + 1 <= n)
		{
			long double temp = point[i + 1].d - point[i].d;
			temp = min(temp, 2 * PI - temp);
			if(minn > temp)
			{
				minn = temp;
				res1 = point[i].id, res2 = point[i + 1].id;
			}
		}
	}
	printf("%d %d\n", res1, res2);
	return 0;
}

D. Igor In the Museum

题意:

给定n * m的矩阵, “.“表示空地,”“表示障碍,给定k个查询,每次输出当前左边周围有多少个”

思路:

观察数据范围,直接暴力铁TLE
可以发现同属于一个连通块内的点,其所对应的答案是一定的,可以直接bfs预处理所有的".",那么同属一个连通块中的点的ans都是一样的。时间复杂度O(n * m)

void bfs(int sta_x, int sta_y)
{
	int cnt = 0;
	queue <PII> alls;
	alls.push({sta_x, sta_y}), book[sta_x][sta_y] = true;
	vector <PII> cc;
	cc.push_back({sta_x, sta_y});
	while(!alls.empty())
	{
		auto t = alls.front();
		alls.pop();
		for(int i = 0 ; i < 4 ; i ++)
		{
			int temp_x = t.first + dx[i];
			int temp_y = t.second + dy[i];
			if(temp_x >= 1 && temp_x <= n && temp_y >= 1 && temp_y <= m)
			{
				if(mm[temp_x][temp_y] == '*')
				{
					cnt ++;
				}
				else 
				{
					if(!book[temp_x][temp_y])
					{
						alls.push({temp_x, temp_y});
						cc.push_back({temp_x, temp_y});
						book[temp_x][temp_y] = true;
					}
				}
			}
		}
	}
	for(auto t : cc)
	ans[t.first][t.second] = cnt;
}
int main()
{
	
	scanf("%d %d %d", &n, &m ,&k);
	for(int i = 1 ; i <= n ; i ++)
	{
		scanf("%s", mm[i] + 1);
	}
	for(int i = 1 ; i <= n ; i ++)
	{
		for(int j = 1 ; j <= m ; j ++)
		{
			if(mm[i][j] == '.' && !book[i][j])
			{
				bfs(i, j);
			} 
		}
	}
	for(int i = 1 ; i <= k ; i ++)
	{
		int x, y;
		scanf("%d %d", &x, &y);
		printf("%d\n", ans[x][y]);
	}
	return 0;
}

E. Chocolate Bar

题意:

将一个n * m的矩阵切成一组总大小为k的方块,可横着切也可竖着切,每次切矩阵的花费为所切长度的平方,求最小的花费.

思路:

分析题意,可以发现,存在多组查询(4e4),且每组查询涉及到n、m及k,可以提前预处理出答案,然后O(1)查询。
尝试是否可以DP求解。
发现存在递推关系,那么可以DP
f[i][j][k]:将i * j的矩阵切成k块的所有合法集合
属性:min
状态转移:
考虑横切:假设t为形成的其中一个矩形的长度,那么i - t为另一个矩形的长度
f [ i ] [ j ] [ k ] = m i n ( f [ i ] [ j ] [ k ] , f [ t ] [ j ] [ t t ] + f [ i − t ] [ j ] [ k − t t ] + j ∗ j ) f[i][j][k] = min(f[i][j][k], f[t][j][tt] + f[i - t][j][k - tt] + j * j) f[i][j][k]=min(f[i][j][k],f[t][j][tt]+f[it][j][ktt]+jj)
竖切同理。
初始化:
所求为min,根据DP定义,起点状态为f[i][j][i * j] = f[i][j][0] = 0, 其他为INF。

int f[40][40][60];
int main()
{
	for(int i = 1 ; i <= 35 ; i ++)
	{
		for(int j = 1 ; j <= 35 ; j ++)
		{
			for(int k = 1 ; k <= 50 ; k ++)
			{
				f[i][j][k] = INF;
			}
			f[i][j][i * j] = 0; 
		}
	}
	for(int i = 1 ; i <= 35 ; i ++) // 
	{
		for(int j = 1 ; j <= 35 ; j ++)
		{
			for(int k = 1 ; k <= 50 ; k ++)
			{
				for(int t = 1 ; t <= i - 1 ; t ++) //横向切 
				{
					for(int tt = 1 ; tt <= k; tt ++)
					{
						if(t * j >= tt && i - t > 0 && (i - t) * j >= k - tt)
						f[i][j][k] = min(f[i][j][k],f[t][j][tt] + f[i - t][j][k - tt] + j * j);
					}
				}
				for(int t = 1 ; t <= j - 1 ; t ++) //竖着   t <= 1
				{
					for(int tt = 1 ; tt <= k; tt ++)
					{ // f[1][2][1] =               f[1][1][1] + f[1][1][0] + i * i
						if(i * t >= tt && j - t > 0 && i * (j - t) >= k - tt)
						f[i][j][k] = min(f[i][j][k],f[i][t][tt] + f[i][j - t][k - tt] + i * i);
					}
				}
			}
		}
	}
	int T;
	scanf("%d", &T);
	while(T --)
	{
		int n, m, k;
		scanf("%d %d %d", &n, &m, &k);
		printf("%d\n", f[n][m][k]);
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值