当前位置: 首页 > news >正文

Codeforces 1060 Div2(ABC1C2D)

前言

看到这场是C1和C2之后,好消息:大概率三题有了,坏消息:大概率四题无了qwq

一、A. Notelock

怎么感觉最近div2的A题比以前难了,以前都能五分钟开A的,现在多少得看一会儿……

#include <bits/stdc++.h>
using namespace std;/*   /\_/\
*   (= ._.)
*   / >  \>
*/typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;void solve()
{int n,k;cin>>n>>k;string s;cin>>s;s=" "+s;int ans=0;for(int i=1;i<=n;i++){if(s[i]=='0'){continue;}int j=i-1;while(j>=1&&s[j]=='0'){j--;}if(i-j>=k||ans==0){ans++;}}cout<<ans<<endl;
}signed main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);int t=1;cin>>t;while(t--){solve();    }return 0;
}

其实因为这个题的数据量不大,那么就考察每一个1,每次去找前一个1的位置。如果和前一个1的间距大于等于k,那么这个位置的1就需要保护一下。

其实设个变量记一下前一个1的位置即可,不知道赛时在想什么,这几场打得依托……

二、B. Make it Zigzag

#include <bits/stdc++.h>
using namespace std;/*   /\_/\
*   (= ._.)
*   / >  \>
*/typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;void solve()
{int n;cin>>n;vector<ll>a(n+1);for(int i=1;i<=n;i++){cin>>a[i];}vector<ll>maxx(n+1);for(int i=1;i<=n;i++){maxx[i]=max(maxx[i-1],a[i]);}for(int i=2;i<=n;i+=2){a[i]=maxx[i];}ll ans=0;for(int i=2;i<=n;i+=2){if(a[i]<=a[i-1]){ans++;}if(i+1<=n&&a[i]<=a[i+1]){ans+=a[i+1]-a[i]+1;a[i+1]=a[i]-1;}}cout<<ans<<endl;
}signed main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);int t=1;cin>>t;while(t--){solve();    }return 0;
}

首先,因为要让偶数位置的数比两侧的数都大,且操作1的次数不限,那么肯定可以上来先对每个偶数位置用一次操作1,这样肯定是不会亏的。之后,若在原来数组中,对于某个偶数位置的数,有前面位置的数比这个数大,那么经过操作1,当前偶数位置的数至少等于前面位置的数,那么此时就只需要用一次操作2把前面位置的数压下去即可。但若后面位置的数比这个数大,就需要用多次操作2把后面的数压到当前数-1了。

三、C1. No Cost Too Great (Easy Version)

越来越不会贪心了……

#include <bits/stdc++.h>
using namespace std;/*   /\_/\
*   (= ._.)
*   / >  \>
*/typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;const int MAXN=2e5+5;vector<vector<int>>prime(MAXN+1);void solve()
{int n;cin>>n;vector<ll>a(n+1);for(int i=1;i<=n;i++){cin>>a[i];}vector<ll>b(n+1);for(int i=1;i<=n;i++){cin>>b[i];}map<int,int>cnts;for(int i=1;i<=n;i++){for(auto x:prime[a[i]]){cnts[x]++;}}if(cnts.empty()){cout<<2<<endl;return ;}for(auto [k,c]:cnts){if(c>1){cout<<0<<endl;return ;}}if(cnts.begin()->first==2){cout<<1<<endl;return ;}for(int i=1;i<=n;i++){for(auto x:prime[a[i]]){cnts[x]--;}for(auto x:prime[a[i]+1]){if(cnts[x]>0){cout<<1<<endl;return ;}}for(auto x:prime[a[i]]){cnts[x]++;}}cout<<2<<endl;
}signed main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);for(int i=2;i<=MAXN;i++){if(!prime[i].empty()){continue;}for(int j=i;j<=MAXN;j+=i){prime[j].push_back(i);}}int t=1;cin>>t;while(t--){solve();    }return 0;
}

首先最基本的可以想到,若存在两个数有公因数,那么答案就是0,那么就可以考虑统计每个数每个质因子出现的次数,若存在一个质因子出现次数大于1,那么答案就是0。其次,若全都是1,即统计质因子词频的map是空的,那么就只需要把两个1加成两个2即可,所以答案就是2。之后,若最小的质因子是2,那么就说明只有一个偶数,其他全是奇数,那么就只需要用一次把某个奇数加成偶数即可。

之后,若都不满足,那么就说明全是奇数,此时首先最劣的情况就是直接对两个奇数都加1变成两个偶数即可。之后,若存在一个数加1后的数和某个数有公因子,那么直接对这个数加1即可。举个例子,对于[3,11],可以直接对11加1变成12,那么此时就和3有公因子3了。所以可以考虑枚举每个数,先把这个数的质因子的减去,再统计这个数加1的结果的质因子,若出现次数大于0,那么就说明可以用一次就满足条件了,否则最后输出2即可。

四、C2. No Cost Too Great (Hard Version)

#include <bits/stdc++.h>
using namespace std;/*   /\_/\
*   (= ._.)
*   / >  \>
*/#define dbg(x) cout<<#x<<" "<<x<<endl
#define vdbg(a) for(auto x:a) cout<<x<<" ";cout<<endl
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;const int MAXN=2e5+5;//prime[i]:数字i的质因数
vector<vector<int>>prime(MAXN+1);void solve()
{int n;cin>>n;vector<ll>a(n+1);for(int i=1;i<=n;i++){cin>>a[i];}vector<ll>b(n+1);for(int i=1;i<=n;i++){cin>>b[i];}//和C1类似,要么把两个数加成偶数,要么让一个数增加两次//对于第一种情况,只需要检查a[i]+1是否与另一个数有公因数即可//否则就直接对最小的两个数,即b[1]和b[2]操作让其变成偶数即可//对于第二种情况,只需要检查最小值b[1]即可//因为若对元素x进行了k次操作,那么其实可以直接对b[1]和b[x]进行操作//因为必然存在b[1]+b[x]<=k*b[x]vector<int>idx(n+1);for(int i=1;i<=n;i++){idx[i]=i;}sort(idx.begin()+1,idx.end(),[&](int x,int y){return b[x]<b[y];});//将两个最小值改成偶数ll ans=b[idx[1]]+b[idx[2]];map<int,int>cnts;for(int i=1;i<=n;i++){for(auto x:prime[a[i]]){//有共同的质因子if(cnts[x]>0){ans=0;}cnts[x]++;}}//考虑对某个数用一次for(int i=1;i<=n;i++){//扣掉a[i]for(auto x:prime[a[i]]){cnts[x]--;}//考虑a[i]+1for(auto x:prime[a[i]+1]){if(cnts[x]>0){ans=min(ans,b[i]);}}//加回来for(auto x:prime[a[i]]){cnts[x]++;}}//除了最小值以外其他数的全部质因子vector<int>all;for(int i=1;i<=n;i++){if(i==idx[1]){continue;}for(auto x:prime[a[i]]){all.push_back(x);}}for(auto x:all){//把a[idx[0]]加成x的倍数需要的次数ll cnt=x-(a[idx[1]]%x);if(cnt==x){cnt=0;}ans=min(ans,cnt*b[idx[1]]);}cout<<ans<<endl;
}signed main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);for(int i=2;i<=MAXN;i++){if(!prime[i].empty()){continue;}for(int j=i;j<=MAXN;j+=i){prime[j].push_back(i);}}int t=1;cin>>t;while(t--){solve();    }return 0;
}

其实顺着C1看C2真不难,但不知道为啥赛时就是没写出来……

其实情况和C1差不多,对于把两个数加成偶数的情况,其实只需要对b[i]最小的两个操作即可。对于把一个数加1使得和另一个数有公因数的情况,就只需要考察每个a[i]+1即可。

和C1不一样的是,考虑在一个元素上进行超过1次的操作的情况,这里,其实只需要考虑对b[i]最小值进行超过一次操作的情况即可,因为若对一个元素进行了超过一次的操作,其一定是劣于让b[i]最小值和这个元素各加1的情况。那么对于第二种情况,可以考虑对b数组从小到大排序,找出最小值。然后可以将除了最小值以外的数的质因子全都存起来,然后考察这些所有的质因子,找出把最小值加成其倍数的次数,然后看看能否把ans更新得更小即可。

五、D. Catshock

队里前辈的思路太强了……

#include <bits/stdc++.h>
using namespace std;/*   /\_/\
*   (= ._.)
*   / >  \>
*/typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;void solve()
{int n;cin>>n;vector<vector<int>>g(n+1);for(int i=0,u,v;i<n-1;i++){cin>>u>>v;g[u].push_back(v);g[v].push_back(u);}//考虑对每个节点进行染色,将其变成一张二分图//每当猫走的时候,其所在节点的颜色就会发生变化,所以删除另一种颜色的节点必然安全vector<int>color(n+1);color[1]=1;auto coloring=[&](auto &&self,int u,int fa)->void{for(auto v:g[u]){if(v!=fa){color[v]=color[u]^1;self(self,v,u);}}};coloring(coloring,1,0);//当前所在节点的颜色int cur=1;vector<string>ans;auto dfs=[&](auto &&self,int u,int fa)->void{//先往下扎,删除孩子节点for(auto v:g[u]){if(v!=fa){self(self,v,u);}}//该删除当前节点u了//当前所在的颜色和该节点相同 -> 走一步if(color[u]==cur){ans.push_back("1");cur^=1;}//上一次是删除操作 -> 走两次 -> 走到颜色相同的节点if(!ans.empty()&&ans.back()[0]=='2'){ans.push_back("1");ans.push_back("1");}if(u==n){return ;}ans.push_back("2 "+to_string(u));};//从n节点开始 -> 从离路径最远的地方开始删dfs(dfs,n,0);cout<<ans.size()<<endl;for(auto s:ans){cout<<s<<endl;}cout<<endl;
}signed main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);int t=1;cin>>t;while(t--){solve();    }return 0;
}

首先上来把这棵树看作一张二分图的这个思路就想不到,最近abc那次图论场才第一次见二分图这个概念。在对每个节点染色后,每当猫走一次,其所在节点的颜色都会发生改变,那么此时删除另一种颜色的节点必然是安全的。那么在dfs染色后,考虑从n号节点开始再dfs一遍,从叶节点,即离当前路径最远的点开始删。所以每次先往下扎,去删除孩子节点,那么当回来时,其孩子节点一定是都删完的,那么此时若猫所在的节点和当前节点的颜色相同,就需要让猫走一步。而若上次就是删除操作,那么就需要让猫走两步,这样既避免了连续删除,也保证了猫所在节点的颜色不会改变,最后再把当前节点删了即可。

总结

多学多练多想吧……加油!!

END

http://www.dtcms.com/a/529938.html

相关文章:

  • 代码随想录 617.合并二叉树
  • 上贵州省建设厅的网站深圳网站制作公司讯
  • 为什么要做一个营销型网站揭阳网站制作软件
  • 集团网站设计特性怎样将网站建设后台装到云上
  • 二手交易平台网站的建设青岛手机端网络推广培训
  • C++ brpc Channel 管理封装方案
  • 合肥网站建设报价做美食教程的网站
  • 企业网站空间买虚拟主机网站做后怎么可以在百度搜索到
  • 网站建设部岗位职责直播软件开发公司
  • app免费制作网站模板北京最新新闻
  • 网站建设物理架构服务管理系统
  • 网站备案 法人变更做品牌网站找谁
  • 使用 C# 流式解析 超大XML:按路径遍历子节点的实用方法
  • 网站建设 成都上海网站建设就q479185700顶上
  • 中小企业网站制作广州网络服务公司找赛合公司点个赞科技 网站制作
  • 网站建设 全是乱码百度一下你就知道官网网页版
  • 网站域名注册证明wordpress页面布局插件
  • Java 项目 — 五种创建方式
  • 可以做推文的网站为何公司做的网站很丑
  • 宜春网站开发公司电话可以用来展示的网站
  • custed谁做的网站商品详情页设计模板
  • 【开题答辩全过程】以 布哩民宿预定系统的设计与实现为例,包含答辩的问题和答案
  • 不到网站是为什么深圳开发微信公众号
  • 网站基础建设一般多少钱自己做网站的服务器
  • 平台网站模板素材图片网页设计与网站开发项目
  • 专业建网站平台电商网站需要哪些备案
  • 网站设计维护内容asp.net 网站管理工具 安全
  • AUTOSAR AP通信管理规范:设计背景与技术实现解析
  • 网上订餐网站模板wordpress如何加html
  • 【开发者导航】高性能跨平台数据整理与分析工具:qsv让CSV处理更高效