2021CCPC黑龙江省赛题解ADFHIJKL

本文详细解析了2021年CCPC黑龙江省赛的多项算法题目,涉及区间DP、线性筛、并查集路径压缩、贪心等算法。题目包括蛋糕分块、工厂工作分配、序列维护、关卡挑战等,每道题均给出解题思路和代码实现,展示了在实际竞赛中如何运用数据结构和算法优化解题效率。

2021CCPC黑龙江省赛题解ADFHIJKL

K. Keep Eating

题意

n  (1≤n≤2e5)n\ \ (1\leq n\leq 2\mathrm{e}5)n  (1n2e5)块蛋糕,重量分别为a1,⋯ ,an  (1≤ai≤1e6)a_1,\cdots,a_n\ \ (1\leq a_i\leq 1\mathrm{e}6)a1,,an  (1ai1e6).每次某人只能吃不超过当前蛋糕的重量的一半的重量,且他不吃重量小于k  (2≤k≤1e6)k\ \ (2\leq k\leq 1\mathrm{e}6)k  (2k1e6)的蛋糕.此外,他可合并两块蛋糕,合并的蛋糕的重量等于原来两蛋糕的重量之和.求他最多能吃多少蛋糕.

思路

先将所有蛋糕拼在一起,设总重量为sumsumsum.

①若sum<ksum<ksum<k,则他不能吃到任何蛋糕.

②若sum≥ksum\geq ksumk,最优策略:先吃(sum−k)(sum-k)(sumk)的重量,再吃剩下的kkk的重量中的⌊k2⌋\left\lfloor\dfrac{k}{2}\right\rfloor2k.

​ 不能吃到的重量为⌈k2⌉\left\lceil\dfrac{k}{2}\right\rceil2k,故他能吃到的重量为sum−⌈k2⌉sum-\left\lceil\dfrac{k}{2}\right\rceilsum2k.

代码 -> 2021CCPC黑龙江省赛-K(思维)

void solve() {
	int n, k; cin >> n >> k;
	ll sum = 0;
	while (n--) {
		int a; cin >> a;
		sum += a;
	}
	cout << (sum >= k ? sum - (k + 1) / 2 : 0);
}

int main() {
	solve();
}


J. JOJO’s Factory

题意

有A型机器和B型机器各n  (5≤n≤5e5)n\ \ (5\leq n\leq 5\mathrm{e}5)n  (5n5e5)台,每台A型机器必须与有且只有一台B型机器一起工作,每台B型机器必须与有且只有一台A型机器一起工作.现有m  (0≤m≤2n−3)m\ \ (0\leq m\leq 2n-3)m  (0m2n3)个数对(i,j)  (1≤i,j≤n)(i,j)\ \ (1\leq i,j\leq n)(i,j)  (1i,jn),表示第iii个A型机器与第jjj个B型机器不能一起工作.问最多有多少对机器同时工作.

思路

只考虑A型机器,设nnn台B型机器都无限制,对此求得答案anslanslansl.同理只考虑B型机器,求得答案ansransransr.最终答案ans=min⁡{ ansl,ansr}ans=\min\{ansl,ansr\}ans=min{ ansl,ansr}.

只考虑A型机器,设nnn台B型机器都无限制.一台A型机器能与B型机器工作的充要条件是:该A型机器的出度<n<n<n.

[] (必) 若该A型机器的出度≥n\geq nn,显然它无法与任一B型机器工作.

(充) 只需证明A型机器的出度<n<n<n时能构造出一组解.

​ 考虑最坏的情况,A1A_1A1B1,⋯ ,Bn−1B_1,\cdots,B_{n-1}B1,,Bn1连边,则A1A_1A1要工作只能与BnB_nBn.

​ 再让A2,⋯ ,AnA_2,\cdots,A_nA2,,AnBnB_nBn连边将BnB_nBn占据,此时A1A_1A1无法工作,且当前共连了(2n−2)(2n-2)(2n2)条边.

​ 而边数≤2n−3\leq 2n-32n3,故必能构造出一组解.

代码 -> 2021CCPC黑龙江省赛-J(思维)

const int MAXN = 1e6 + 5;
int n, m;  // 节点数、边数
int outl[MAXN], outr[MAXN];  // 左右节点的出度

void solve() {
	cin >> n >> m;

	int ansl = n, ansr = n;
	while (m--) {
		int i, j; cin >> i >> j;
		outl[i]++, outr[j]++;
		if (outl[i] >= n) ansl--;
		if (outr[j] >= n) ansr--;
	}
	cout << min(ansl, ansr);
}

int main() {
	solve();
}


D. Doin’ Time

题意

有一长度为n  (1≤n≤300)n\ \ (1\leq n\leq 300)n  (1n300)的序列a1,⋯ ,an  (1≤ai≤1e6)a_1,\cdots,a_n\ \ (1\leq a_i\leq 1\mathrm{e}6)a1,,an  (1ai1e6),每次操作可选一个下标xxx,合并axa_xaxax+1a_{x+1}ax+1ax⋅ax+1 mod 1000003a_x\cdot a_{x+1}\ \mathrm{mod}\ 1000003axax+1 mod 1000003,并得到(ax−ax+1)2(a_x-a_{x+1})^2(ax

2021CCPC女生程序设计竞部分题解如下: - **A题公交路线题解**: ```cpp #include <bits/stdc++.h> using namespace std; int main() { int n, x, y, arr[15]={0}; cin >> n >> x >> y; for (int i = 1; i <= n; i++) { cin >> arr[i]; } int m, xx, brr[15]={0}; cin >> m; if(x<y){ for(int i=1;i<=m;i++){ cin>>brr[i]; if(brr[i]!=arr[i+x]){ cout<<"Wrong"<<endl; return 0; } } if(x-1<1||x-m<1){ cout<<"Right"<<endl; return 0; } for(int i=1;i<=m;i++){ if(arr[x-i]!=brr[i]){ cout<<"Right"<<endl; return 0; } } cout<<"Unsure"<<endl; return 0; }else{ for(int i=1;i<=m;i++){ cin>>brr[i]; if(brr[i]!=arr[x-i]){ cout<<"Wrong"<<endl; return 0; } } if(x==n||x+m>n){ cout<<"Right"<<endl; return 0; } for(int i=1;i<=m;i++){ if(arr[x+i]!=brr[i]){ cout<<"Wrong"<<endl; return 0; } } cout<<"Unsure"<<endl; } return 0; } ``` - **C题题解**: 思路是寻找一个最短的 `t`,使得 `t` 不是 `s(l,r)` 的子序列,假设现在位于 `x`,下一步有 `m` 个选择,要使子序列尽可能小,就选择离 `x` 最远的那个字母,直到走出 `r` 为止。问题转化为从 `l` 开始沿着 `_next` 一路往右跳,要跳多少步才能跳到 `> r` 的地方,使用倍增的方法使得 `_next[i][j]` 是 `i` 从 `2^j` 步到达的最远位置。 ```cpp #include<bits/stdc++.h> using namespace std; char s[200100]; int _next[200100][26];//st表 int v[2000100]; int a[26]; int main(){ int m,n; scanf("%d%d",&m,&n); scanf("%s",s+1); for(int i=0;i<=25;i++){ a[i]=n+1; } for(int i=n;i>=0;i--){ for(int j=0;j<m;j++){ v[i]=max(v[i],a[j]); } _next[i][0]=v[i]; if(i)a[s[i]-'a']=i; } for(int j = 1; j < 20; j ++){ for(int i = 0; i <= n; i ++) { int t = _next[i][j - 1]; if(t <= n) _next[i][j] = _next[t][j - 1]; else _next[i][j] = n + 1; } } int q; scanf("%d",&q); while(q--){ int l,r; scanf("%d%d",&l,&r); int ans = 0, now = l - 1; for(int j = 19; ~j; j --) if(_next[now][j] <= r) ans += (1 << j), now = _next[now][j]; printf("%d\n",ans+1); } return 0; } ``` 以上代码分别对应2021CCPC女生程序设计竞A题和C题的题解 [^2][^3]。
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值