Codeforces #635题解
Codeforces round 635赛后解题报告
A. Ichihime and Triangle
#include<bits/stdc++.h>
#define int long long
using namespace std;int read() {char ch=getchar();int f=1,x=0;while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}return f*x;
}int a,b,c,d,n;signed main() {n=read();for(int i=1;i<=n;i++) {a=read();b=read();c=read();d=read();printf("%lld %lld %lld\n",a,c,c);}return 0;
}
B. Kana and Dragon Quest game
Q:不就是不等式吗,小学三年级都会做,说的那么玄乎
A:你说的没错
总结这道题,是一个不等式的小应用,同时用贪心辅助即可,作为CF的div2 B还是很合适的~
多组数据!!!
#include<bits/stdc++.h>
#define int long long
using namespace std;int read() {char ch=getchar();int f=1,x=0;while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}return f*x;
}int n,x,m;signed main() {int t;t=read();while(t--) {x=read();n=read();m=read();while(n&&x>20) {x=x/2+10;n--;}if(m*10>=x) {printf("YeS\n");//这里}else{printf("nO\n");//这里}}return 0;
}
C. Linova and Kingdom
首先我们发现我们要找到深度尽可能大的节点,这样对答案的贡献较大,用堆维护,但是我们来看样例1:
树剖做法
先说树剖的做法,代码不给了。上面提到了,我们发现我们找到的点,尽量要分布在不同链上,这样对答案的减少最小。自然想到维护链的工具:树剖。我们找到一个点后,对其所在的重链或长链打上标记,下次优先找其他链上的点。代码可以自己写下。
贪心做法
我们再来看看贪心。我们发现,一个节点对于答案的贡献是它到根节点的深度减去以它为根的子树的工业城市与它的距离之和。但是由于我们贪心,所以我们肯定在选这个节点前,它的子树全被选过了(因为它的子树里每一个节点,深度都比它大,它们的贡献也比这个节点大),那么简而言之,一个节点的新贡献是这样的:
d e p u − s i z e u dep_u-size_u depu−sizeu
它的每一个子树成员都因为它的出现导致答案减去 1 1 1。所以我们在一遍 dfs 预处理完所有的基本信息后,用堆来维护即可。
这个可能太抽象,我们来模拟一下一组数据:
7 5
1 2
1 3
1 4
3 5
3 6
4 7
图和样例1一样:
我们前面的还是选择了 5 , 6 , 7 5,6,7 5,6,7。现在堆里有 3 3 3 个节点: 2 , 3 , 4 2,3,4 2,3,4 如果我们分别选择了它们,则对答案的新贡献分别是 1 , − 1 , 0 1,-1,0 1,−1,0 (因为其子树里的所有节点都会的答案值都要减 1 1 1),那么我们就选 2 2 2 号节点。然后把 1 1 1 放进去。最后不难发现我们改选择 4 4 4 作为下一个选择的节点,因为他的新贡献值最大(虽然是负的,但是不管如何,都要选满 k k k 个)。
是不是理解了呢,应该很清晰易懂了吧~~
#include<bits/stdc++.h>
#define int long long
using namespace std;int read() {char ch=getchar();int f=1,x=0;while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}return f*x;
}const int maxn=2e5+10;int n,h[maxn],cnt,k,dep[maxn],ans,fa[maxn],size[maxn];
bool ind[maxn],ex[maxn];
priority_queue<pair<int,int> > q;struct edge {int v,next;
}e[maxn<<1];void addedge(int u,int v) {e[++cnt].v=v;e[cnt].next=h[u];h[u]=cnt;
}void dfs(int u,int father) {int num=0;size[u]=1;for(int i=h[u];i;i=e[i].next) {int v=e[i].v;if(v!=father) {num++;dep[v]=dep[u]+1;fa[v]=u;dfs(v,u);size[u]+=size[v];}}if(!num) {q.push(make_pair(dep[u],u));ex[u]=1;}
}void cfs(int u,int fa,int num) {for(int i=h[u];i;i=e[i].next) {int v=e[i].v;if(v!=fa) {cfs(v,u,num+1-ind[u]);}}if(ind[u])ans+=num;
}signed main() {n=read();k=read();for(int i=1;i<n;i++) {int a=read(),b=read();addedge(a,b);addedge(b,a);}dfs(1,0);for(int i=1;i<=k;i++) {pair<int,int> pr=q.top();q.pop();ind[pr.second]=1;if(!ex[fa[pr.second]]) {q.push(make_pair(dep[fa[pr.second]]-size[fa[pr.second]]+1,fa[pr.second]));ex[fa[pr.second]]=1;}}cfs(1,0,0);cout<<ans<<endl;return 0;
}
D. Xenia and Colorful Gems
看到这个题,我们作为一种贪婪的生物,肯定会想到贪心,也就是找到尽量相近的 x , y , z x,y,z x,y,z。
Q:这不是废话吗。这是题意啊
A:这就是废话。
但是,这让我们知道我们直接去求这三个数,是不现实的。那么我们会想到一个算法:二分答案
Q1:为什么这样能找到最优解呢?
A1:我们想象一下这个过程,相当于我们对于每一个数,找了最优解,那么相当于一个枚举,只不过,有章法,有顺序,有道理。
Q4:加个注释好吗?
A4:不了,原因:1.锻炼自我的代码能力,一下代码仅供参考。2.我懒
如果需要注释,可以私信我哟~~
#include<bits/stdc++.h>
#define int long long
using namespace std;int read() {char ch=getchar();int f=1,x=0;while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}return f*x;
}const int maxn=1e5+10,inf=0x7fffffffffffffff;int n[3],c[3][maxn];int calc(int x,int y,int z) {return (x-y)*(x-y)+(y-z)*(y-z)+(x-z)*(x-z);
}signed main() {int t=read();while(t--) {for(int i=0;i<3;i++) {n[i]=read();}for(int i=0;i<3;i++) {for(int j=1;j<=n[i];j++) {c[i][j]=read();}sort(c[i],c[i]+n[i]+1);}int ans=inf;for(int i=0;i<3;i++) {for(int j=0;j<3;j++) {for(int k=0;k<3;k++) {if(i!=j&&j!=k&&i!=k) {for(int q=1;q<=n[i];q++) {int p1=lower_bound(c[j],c[j]+n[j]+1,c[i][q])-c[j];int p2=upper_bound(c[k],c[k]+n[k]+1,c[i][q])-c[k];if(p1!=n[j]+1&&p2!=1) {p2--;ans=min(ans,calc(c[i][q],c[j][p1],c[k][p2]));}}}}}}printf("%lld\n",ans);}return 0;
}
E. Kaavi and Magic Spell
定状态
我们定义 f i , j f_{i,j} fi,j 为用 s 1 s_1 s1 到 s j − i + 1 s_{j-i+1} sj−i+1 根据题目中的规则,填充 t i t_i ti 到 t j t_j tj 的方案数。
我们在定义 S , T S,T S,T 的长度为 n , m n,m n,m。
转移方程
很明显,这是一个区间DP的定义方式,所以转移方程很好想,应该是这样的:
f i , j = max { f i + 1 , j + f i , j − 1 ( i > m ∣ t i = s j − i ) & ( j > m ∣ t j = s j − i ) f i + 1 , j i > m ∣ t i = s j − i f i , j − 1 j > m ∣ t j = s j − i 0 f_{i,j}=\max \begin{cases} f_{i+1,j}+f_{i,j-1}&(i>m|t_i=s_{j-i})\&(j>m|t_j=s_{j-i})\\f_{i+1,j}&i>m|t_i=s_{j-i}\\f_{i,j-1}&j>m|t_j=s_{j-i}\\0 \end{cases} fi,j=max⎩⎪⎪⎪⎨⎪⎪⎪⎧fi+1,j+fi,j−1fi+1,jfi,j−10(i>m∣ti=sj−i)&(j>m∣tj=sj−i)i>m∣ti=sj−ij>m∣tj=sj−i
Q1:为什么 i i i 会大于 m m m?
A1:因为我们拼出的字符串 A A A 的长度不一定小于 T T T 的长度,所以在拼完前 m m m 个字符,后面可以随便拼,故 i > m i>m i>m 时,可以随便拼字符。
边界
我们在上面说过: i , j ⩾ m i,j\geqslant m i,j⩾m 是可以的,所以 i i i 要循环到 n n n。但是注意区间DP的常见错误!先枚举长度,再枚举起点!
初始化
很明显我们要初始化 f i , i f_{i,i} fi,i。
f i , i = max { 2 i > m ∣ t i = s 1 0 f_{i,i}=\max \begin{cases}2&i>m|t_i=s_1\\0\end{cases} fi,i=max{20i>m∣ti=s1
和上面的转移方程很类似。原因不再赘述。
写代码
注意我用的是 string,一定要注意下表从 0 0 0 开始。所以可能会和上面的转移方程有一些不同之处(主要是边界)。
#include<bits/stdc++.h>
#define int long long
using namespace std;int read() {char ch=getchar();int f=1,x=0;while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}return f*x;
}const int maxn=3000+10,mod=998244353; int n,m,f[maxn][maxn];
string s,t;signed main() {cin>>s>>t;n=s.size();m=t.size();for(int i=0;i<n;i++) {if(i>=m||t[i]==s[0]) {f[i][i]=2;}}for(int len=2;len<=n;len++) {for(int i=0;i<n;i++) {if(len+i-1>=n) {break;}int j=len+i-1;if(i>=m||t[i]==s[len-1]) {f[i][j]+=f[i+1][j];}if(j>=m||t[j]==s[len-1]) {f[i][j]+=f[i][j-1];}f[i][j]%=mod;}}int ans=0;for(int i=m-1;i<n;i++){ans+=f[0][i];ans%=mod;}cout<<ans<<endl;return 0;
}
F. Yui and Mahjong Set
Codeforces #635题解相关推荐
- Dominated Subarray[codeforces 1257C]题解
Dominated Subarray[codeforces 1257C] CF-1257C(Dominated Subarray) 题目 输入 输出 题目大意 样例输入 样例输出 CF-1257C(D ...
- Codeforces 833B 题解(DP+线段树)
题面 传送门:http://codeforces.com/problemset/problem/833/B B. The Bakery time limit per test2.5 seconds m ...
- Codeforces 1344 题解
A 假设所有的 \((i+a_i)\) 模 \(n\) 意义下构成排列则答案为 YES,否则为 NO. 时间复杂度 \(O(n)\) 或 \(O(n\log n)\). 代码: 79150268 B ...
- Codeforces 1314 题解
这场整体质量感觉可以算 2020 年度(目前为止)最垃圾. A 按数值从小到大扫描,维护一个优先队列,每遇到一个数加入队列,每次数值发生 \(+1\) 时弹掉队列中价值最大元素,然后把此时队列中所有元 ...
- Codeforces 1338 题解
A 对于每个 \(i\) 我们求出 \(b_i\) 表示 \(i\) 这个数最少要增加多少(\(\max^i_{j=1}a_j-a_i\)),答案等于最小的 \(k\) 使得 \(2^k-1\ge \ ...
- Codeforces 1149 题解
A 特判全是 \(2\),对于有 \(1\) 的情况把 \(1\) 放到第二个和最后. 时间复杂度 \(O(n)\). 代码: 76492031 B 考虑只有一次询问的情况,有一个 \(O(n^3)\ ...
- Codeforces 1025 题解
A 若 \(n=1\) 则答案为 YES,否则答案为 YES 当且仅当存在两个相同的字符. 时间复杂度 \(O(n)\). 代码: 76484733 B 求出所有 \(\text{lcm}(a_i,b ...
- Codeforces 1188 题解
A 首先对于 A1 题,可以加减任意实数,结论是答案为 YES 当且仅当没有度数为 \(2\) 的点.必要性显然,充分性通过下面的构造来证明. A2 题的构造:考虑随便找一个叶子节点为根,记为 \(r ...
- codeforces #1 题解
codeforces1A 题目链接:http://codeforces.com/problemset/problem/1/A 题意:给定一个n*m的矩形,然后给一个a*a的地板,求最少需要多少地板可以 ...
最新文章
- 关于微服务的7个疑问和解答!
- 支持实践教学:清华大数据能力提升项目举办CIKM AnalytiCup2017冠军团队经验分享会
- 继续咸鱼——2.18
- 解决requests-SSL: CERTIFICATE_VERIFY_FAILED]问题
- 用excel 2016连接mysql_excel导入mysql数据库方法(最新,2016年2月19日)
- Verilog HDL中使用系统任务 $readmemh遇到问题及解决方法
- Python爬取王者荣耀皮肤
- Android-SDK下载及安装配置教程
- 鸟哥的Linux私房菜知识点总结(持续更新中)
- 【短期投资理财 一】信用卡入门操作
- 漫画 | 揭密微信诞生记之民间传说
- 高频课设-基于STM32的温度无线监测系统
- mdk是什么意思_MDK是什么意思
- 菜鸡前端面试题整理日记
- java邮箱验证码_Java实现邮箱验证码
- table 嵌套table 让内部table高度填满外部的td
- 近8年的测试人员跟你细谈如何从一个测试小白到大佬的转变
- VI命令使用大全(删除精华)
- 太空射击第08课: 改进的碰撞
- 十二经络运行时间及养生