首页 > 其他分享 >周赛Round26总结1

周赛Round26总结1

时间:2024-03-02 21:55:05浏览次数:18  
标签:总结 周赛 return int ll long mod dp Round26

预计得分500,实际得分400,挂了20 + 50 + 30分。

T1 移动 move

题目描述:

\(n\)个二维向量\((X_{i}, Y_{i})\),随便选择\(k\)个,其中\(0<=k<=n\),起点是\((0, 0)\),每次移动后的位置是\((s+x_{i},t+y_{i})\),求终点\(|s| + |t|\)的最大值。

分析:

分类讨论。\((X_{i}, Y_{i})\)可以分到四个象限之中去,然后我们的\((s, t)\)也有在四种象限的情况。然后我们贪心的讨论,如果加入点的坐标和自己所属象限的全部相反,那么一定不用讨论,如果是完全一样的,那么直接加上,如果有一个不一样,那么我们可以讨论一下可以选的是谁,选择更优还是不选择更优。四个象限全部写完实在是太复杂了,所以我们用函数。

但是由于我的智慧,最后一个分类讨论是\(solve(-1, -1)\),我写得是\(solve(1, 1)\)居然还有八十分,我太感动了!!!

#include <bits/stdc++.h>
using namespace std;
const int N = 600005;
typedef long long ll;
int n;
ll x[N], y[N], sumx = 0, sumy = 0, ans = 0;
int pdx[N], pdy[N];
ll Abs(ll a) {return a < 0 ? -a : a; } 
void solve(int a, int b)
{
	sumx = 0, sumy = 0;
	for (int i = 1; i <= n; ++ i)
	{
		if(pdx[i] != a && pdy[i] != b) continue;
		if(pdx[i] == a && pdy[i] == b) sumx += x[i], sumy += y[i];
		else if(pdx[i] == a && Abs(x[i]) > Abs(y[i])) sumx += x[i], sumy += y[i];
		else if(pdy[i] == b && Abs(y[i]) > Abs(x[i])) sumx += x[i], sumy += y[i];
	}
	ans = max(ans, Abs(sumx) + Abs(sumy));
}
int main()
{
	scanf("%d", &n);
	for (int i = 1; i <= n; ++ i)
	{
		scanf("%lld %lld", &x[i], &y[i]);
		if(x[i] < 0) pdx[i] = -1;
		else pdx[i] = 1;
		if(y[i] < 0) pdy[i] = -1;
		else pdy[i] = 1; 
	}
	solve(1, 1);
	solve(1, - 1);
	solve(- 1, 1);
	solve(- 1, - 1);
	printf("%lld", ans); 
	return 0;
} 

T2 双色图案 bicoloring (CF 1051D)

分析:

这是一个dp,状态就是枚举前面的块是什么样子,可能是\(01\),\(10\),\(11\),\(00\),然后枚举后面的状态是什么样子,可能是\(01\),\(10\),\(11\),\(00\).然后看\(16\)种匹配方式分别会造成怎么样的收益就可以了。Ca喜欢节约空间,所以Ca使用了滚动数组。显然数组应该是要开\(long long\)的,但是Ca为了节约空间,我们在计算过程中开\(long long\),数组还是使用\(int\)类型。

计算时\((long long) + (int)\)类型计算出来的答案是\((long long)\),如果使用\((int) + (int) + (long long)\),计算前面两个是\((int)\),后面会成为\((long long)\),但你无法保证前面不会炸,\((long long)((int) + (int))\),会先计算里面的\((int)\),再变成\((long long)\),但是显然你无法保证里面的计算不会炸掉。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n, k;
const int mod = 998244353;
int dp[2][2105][2][2];
int main()
{
	scanf("%d %d", &n, &k);
	dp[1][2][0][1] = 1, dp[1][1][0][0] = 1, dp[1][1][1][1] = 1, dp[1][2][1][0] = 1;
	for (int i = 2; i <= n; ++ i)
	{
		int x = (i & 1), y = x ^ 1;
		for (int j = 1; j <= k; ++ j)
		{
			dp[x][j][0][0] = dp[x][j][0][1] = dp[x][j][1][0] = dp[x][j][1][1] = 0;
			for (int a = 0; a <= 1; ++ a)
			{
				for (int b = 0; b <= 1; ++ b)
				{
					for (int c = 0; c <= 1; ++ c)
					{
						for (int d = 0; d <= 1; ++ d)
						{
							if(a != b)
							{
								if(c != a && d != b && j >= 2) dp[x][j][c][d] = (ll)(dp[x][j][c][d] + dp[y][j - 2][a][b]) % mod;
								else dp[x][j][c][d] = (ll)(dp[x][j][c][d] + dp[y][j][a][b]) % mod;	
							}
							else
							{
								if(c == a && d == b) dp[x][j][c][d] = (ll)(dp[x][j][c][d] + dp[y][j][a][b]) % mod;
								else dp[x][j][c][d] = (ll)(dp[x][j][c][d] + dp[y][j - 1][a][b]) % mod;
							}
						}
					}
				}
			}
		}
	}
	printf("%lld", (((ll)dp[n & 1][k][0][1] + dp[n & 1][k][1][0] + dp[n & 1][k][1][1] + dp[n & 1][k][0][0]) % mod + mod) % mod);
	return 0;
}

T3 星际货运 express

最小生成树 + 贪心。

最小生成树要选择代价最小的边,题目的性质也保证了是选择三元组中最小的,所以这两个是不冲突的,如果有重复,用并查集找一下就可以了。但是一口气放\(N^2\)条边显然是空间时间都去世,所以说我们要贪心一下。单独的\(x\),\(y\),\(z\)最小的肯定是优先产生贡献,所以可以把三种分别弄出来排序。大的减去小的一定是正数。这样选出来的后面减去前面一个的边一定可以围城一棵树,因为所有的点都有一个有关系的节点,并不是孤立的。

关于最小生成树的证明:假设\(T\)是一棵最小生成树,我们并不选择所有最小的可以选择的边构成它,也就是存在\((u, v)\),\(w[u][v] < w[u][r]\),其中\((u, r)\in T\),我们完全可以把\((u, r)\)断掉,因为是一棵树,所以u和r就不再联通,因为在满足之前选\((u, v)\), \(u\), \(v\)是不连通的,所以再连起来是完全可以的成为一棵新的树的,并且答案会更优秀。

#include <bits/stdc++.h>
using namespace std;
const int N = 200005;
typedef long long ll;
ll ans = 0;
int n, fa[N], cnt = 0, tot = 0;
int findset(int x)
{
	if(fa[x] == x) return x;
	return fa[x] = findset(fa[x]);
}
struct node
{
	ll w;
	int id;
}px[N], py[N], pz[N];
struct edge
{
	int u, v;
	ll w;
}e[N << 2];
bool cmp(node a, node b) {return a.w < b.w; }
bool ecmp(edge a, edge b) {return a.w < b.w; } 
void Kruskal()
{
	sort(e + 1, e + cnt  + 1, ecmp);
	for (int i = 1; i <= cnt; ++ i)
	{
		int x = findset(e[i].u), y = findset(e[i].v);
		if(x == y) continue;
		ans = ans + e[i].w;
		fa[x] = y, tot ++;
		if(tot == n - 1) break;
	}
	return ;
}
int main()
{
	scanf("%d", &n);
	for(int i = 1; i <= n; ++ i)
	{
		fa[i] = i;
		scanf("%lld %lld %lld", &px[i].w, &py[i].w, &pz[i].w);
		px[i].id = py[i].id = pz[i].id = i;
	}
	sort(px + 1, px + n + 1, cmp);
	sort(py + 1, py + n + 1, cmp);
	sort(pz + 1, pz + n + 1, cmp);
	for (int i = 2; i <= n; ++ i)
	{
		e[++ cnt].w = px[i].w - px[i - 1].w, e[cnt].u = px[i - 1].id, e[cnt].v = px[i].id;
	}
	for (int i = 2; i <= n; ++ i)
	{
		e[++ cnt].w = py[i].w - py[i - 1].w, e[cnt].u = py[i - 1].id, e[cnt].v = py[i].id;
	}
	for (int i = 2; i <= n; ++ i)
	{
		e[++ cnt].w = pz[i].w - pz[i - 1].w, e[cnt].u = pz[i - 1].id, e[cnt].v = pz[i].id;
	}
	Kruskal();
	printf("%lld", ans);
	return 0;
}

T4 圆数 round

分析:

其实不难发现是一个数位dp的模板(以前觉得数位dp好难,简直不是人做的),但是就是不能理解这个奇怪的东西,其实它就是一个搜索的记忆化。我们定义\(dp[i][a][j][k][b]\)表示还剩下i个数字没有填;剩下的数字可不可以随便选择0可以,1不可以;一共填充了几个1;一共填充了几个0;前面有没有前导0。如果我们遇到了一样的情况就可以直接返回。一共有\(63 \times 63 \times 63\times 2\times2\)种情况,没遇到就更新,遇到了就返回,所以说复杂度就是这些状态的总数量。

对于此题中每一个不一样的数字,我们都需要重新更新,因为对应状态中是上限的条件会产生变化,因为不同的数字上限是不样的,所以答案也会产生一定的变化。

#include <bits/stdc++.h>
using namespace std;
const int N = 105;
typedef __int128 ll;
void read(ll &x)
{
	char c = getchar(); x = 0;
	while(c < 48 || c > 57) {c = getchar(); }
	while(c >= 48 && c <= 57) {x = (x << 1) + (x << 3) + (c ^ 48); c = getchar(); }
	return ;
}
void write(ll x)
{
	if(x >= 10) write(x / 10);
	putchar(x % 10 + '0');
	return ;
}
ll l, r, ans = 0, dp[65][2][65][65][2];
int a[N], cnt = 0;
ll dfs(int pos, bool limit, int sm1, int sm0, bool pre)
{
	if(dp[pos][limit][sm1][sm0][pre] != -1) return dp[pos][limit][sm1][sm0][pre];
	if(pos + sm0 < sm1) return 0;
	if(pos == 0)
	{
		if(sm0 >= sm1) return 1;
		return 0;
	}
	ll sum = 0; 
	bool up = limit ? a[pos] : 1;
	for (int i = 0; i <= up; ++ i)
	{
		sum += dfs(pos - 1, limit & (i == up), sm1 + (i == 1), sm0 + (i == 0 && !pre), pre & (i == 0));
	}
	if(dp[pos][limit][sm1][sm0][pre] == -1) dp[pos][limit][sm1][sm0][pre] = sum;
	return sum;
}
ll solve(ll x)
{
	cnt = 0;
	for (int i = 0; i <= 63; ++ i)
	{
		for (int j = 0; j <= 63; ++ j)
		{
			for (int k = 0; k <= 63; ++ k)
			{
				for (int a = 0; a <= 1; ++ a)
				{
					for (int b = 0; b <= 1; ++ b) dp[i][a][j][k][b] = -1;
				}
			}
		}
	}
	if(x == 1 || x == 0) return 1;
	while(x) 
	{
		a[++ cnt] = x & 1;
		x >>= 1;
	}
	return dfs(cnt, true, 0, 0, true);
}
int main()
{
	read(l), read(r);
	write(solve(r) - solve(l - 1));
	return 0;
}

标签:总结,周赛,return,int,ll,long,mod,dp,Round26
From: https://www.cnblogs.com/ybC202444/p/18049306

相关文章

  • YL 模拟赛总结 5
    ProblemT1\(m\)个人中间必定有\(m-1\)个空位,剩下\(n-m+1\)个位置可以随意放人,则方案数为\(A^{m}_{n-m+1}\)。T2考虑进行\(dp\)。状态:令\(dp_{i,j}\)表示字符串\(S_{i\simj}\)要变成回文串需要添加的最少字符数。转移:枚举区间左端点\(l\)和长度\(k\),右端点......
  • YL 模拟赛总结 4
    ProblemT1遍历字符串,拿一个桶统计即可。T2当\(x\)为中位数时,我们应当尽量的让整个数列的和变小,然后直接在最后一个上加即可。为了让整个数列有序,和最小的构造的数列应当是\(0,0,\cdot\cdot\cdot,x,x,\cdot\cdot\cdot,x\),此时的和应是\(\lfloor\dfrac{n+1}{2}\rflo......
  • YL 模拟赛总结 3
    ProblemT1累加燃烧度,除以\(m\)即为答案。需要开unsigned__int128,差评。T2若有\(a,b\)满足\(a-c=c-b\),化简此式可得\(a+b=2c\),说明\(a+b\)必须为偶数。于是我们倒序求一遍后缀偶数个数\(os_i\)和奇数个数\(js_i\);然后枚举每一个\(i\),若它是奇数,则它可以和它......
  • 2023-2024第一学期的助教工作总结(教务处老师助教)
    一.帮助老师整理开会后的电子版例会总结,整理各类考试试卷以及完成各类文档二.助教工作的每周时长不定,具体安排是整理电子版例会总结和整理考试试卷三.目前我自己的助教工作还处在初阶阶段,主要是帮助老师处理事情,老师平时很忙,平时帮助老师处理一些小事情,也为老师腾出时间来更......
  • 数学之概率题目总结
    前言如有错误,欢迎各位dalao指出。前置芝士:概率T1题目传送门可以看见,标签是入门,一定非常水。显然,要让小D获胜,我们只需要选出\(max(v,w)\rightarrow6\)这一段的任意一个值即可获胜,注意特判一下\(max(v,w)>6\)的情况就行了。还是比较水。T2题目传送门老师抽我起......
  • 0/1分数规划总结
    前言最近在搞什么树套树,博弈论,啥啥啥的,时间实在紧迫,就先拿0/1规划开刀。0/1分数规划是什么实际上是一类问题。顾名思义,0/1即对于\(n\)个物品,选择或者不选择。分数,即对于每个物体,有两个属性\(a_i,b_i\),选出物品的价值就是\(\dfrac{\suma_i\timesd_i}{\sumb_i\tim......
  • 每日总结
    1.在java中,数组是一个对象,不是一种原生类,对象所以存放在堆中,又因为数组特性,是连续的。2.用户不能调用构造方法,只能通过new关键字自动调用。这句话是错误的。在类内部可以用户可以使用关键字this.构造方法名()调用(参数决定调用的是本类对应的构造方法)在子类中用户可以通过......
  • Linux_Centos_yum报错总结
    ​此篇适用于yum报错【尝试其他镜像】并且【curl外网】不通的情况,此时一般考虑是网络的问题一,出现的报错信息: 此时测试curl/pingwww.baidu.com会发现无法连通 二,解决方法:1,首先查看dns的配置文件/etc/resolv.conf检查这里的nameserver这里有时候会因为第二个网卡......
  • YL 模拟赛总结 15
    ProblemT1感觉是最难的。考虑贪心。首先对牛的按左端点进行排序,然后对于每只鸡去考虑匹配哪头牛。具体地,开一个小根堆,然后对于每只鸡\(t_i\),将\(a_i\let_i\)的牛放入堆中,此时堆中存放的是候选的牛。然后对于堆中的牛,将\(b_i<t_i\)的牛弹出。此时堆中的牛均是合法的......
  • YL 模拟赛总结 14
    Problem省流:三道题写了tjT1见tj。T2见tj。T3见tj。T4二分求出左右端点即可。#include<bits/stdc++.h>usingnamespacestd;intn,q;intp[200031];intmain(){//freopen("haybales.in","r",stdin);//freopen("haybales.out",&quo......