Codeforces Round #674 (Div. 3)A-F题解

2024-01-31 18:38
文章标签 codeforces round div 674 题解

本文主要是介绍Codeforces Round #674 (Div. 3)A-F题解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Codeforces Round #674 (Div. 3)A-F题解

比赛链接:https://codeforces.com/contest/1426

A题
水题不写题解

#include<bits/stdc++.h>
#define ll long long
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;int32_t main()
{IOS;int t;cin>>t;while(t--){int n,x;cin>>n>>x;if(n<3) cout<<1<<endl;else cout<<(n-2)/x+((n-2)%x?1:0)+1<<endl;}
}

B题
简单构造

题意为给定n个2 × \times × 2的矩阵,你可以使用任意次这些矩阵,要求拼出一个m × \times × m的按照主对角线对称的矩阵。询问是否可以构造。

根据矩阵是否在主对角线上,我们可以注意到在对角线上的2 × \times × 2 矩阵也同时需要按照自己的主对角线对称,而不主对角线上的矩阵,两两之间需要互相对称,我们不难发现如果有满足主对角线上矩阵条件的2 × \times × 2 矩阵,那我们把这些矩阵直接铺满非对角线的部分也是满足要求的。

因此直接判断给的2 × \times × 2 矩阵中是否存在自身就是个关于主对角线对称的矩阵即可,同时m需要满足是一个偶数。

#include<bits/stdc++.h>
#define ll long long
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;int num[107][2][2];int32_t main()
{IOS;int t;cin>>t;while(t--){int n,m;cin>>n>>m;bool flag=0;for(int i=0;i<n;i++){for(int j=0;j<2;j++)for(int k=0;k<2;k++)cin>>num[i][j][k];if(num[i][0][1]==num[i][1][0]) flag=1;}if(m%2==0&&flag) cout<<"YES"<<endl;else cout<<"NO"<<endl;}
}

C题
简单构造,暴力或简单结论

题意为一开始的时候数列只有一个数字1,每次操作你可以对数列中的一个数字加1,或者复制某一个数字到数列末尾,问你最少需要多少次操作可以使得这个数列中所有数的值加起来不小于n。

我们注意到每次操作,
如果选择值+1的话只会对整体产生+1的影响,但是这个+1后的值会增加复制操作可增加的最大值。
而复制某一个值会增加一个当前最大的数的值,但是不会对后续操作可增加的最大值产生影响。

我们直接贪心选择先不断对第一个数+1,+1到合适大小后不断复制这个值即可。
假设我们先+1到值为i,那么总的操作次数分为两个部分,第一个部分是+1的次数为i-1,第二个部分是复制数值i的次数,为n/i-1+n%i?1:0。
推到这里之后直接暴力for sqrt(n)已经可以过题。
但是还可以简单地再深入一下,我们对i增加1,会对第一部分的操作次数i-1产生+1的影响,那么在第二部分的n/i-1+n%i?1:0的部分至少要减去1,我们对i的+1操作才是正面的。写过《算竞》上余数之和这个例题可能会比较敏感,或者自己稿纸上写一下也能发现这个规律,此时i的值取sqrt(n)就是最优。当i>=sqrt(n)时,当i变化时,n/i的步长变化不可能大于1,与i<sqrt(n)的情况反过来对应。

#include<bits/stdc++.h>
#define ll long long
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;int32_t main()
{IOS;int t;cin>>t;while(t--){ll n;cin>>n;ll temp=sqrt(n);cout<<temp-1+n/temp-1+(n%temp?1:0)<<endl;}
}

D题
贪心,构造

题意为给定一个数列,不包含0,现在问你最少需要往这个数列中插入几个数字,使得这个数列不存在某个连续的区间的数值和为0。

这里直接采取贪心的策略就是了,从左往右扫过去,对于第一段出现的和为0的区间,我们必定要在中间插入一个数字,可以直接贪心在最右边的一个元素的左侧插入一个“无穷大”的值,这样的话,这个无穷大值左侧的部分都不会和右侧的部分加起来等于0了。

这里区间为0可以用map记录前缀和的出现情况来处理,每次出现某个区间和为0后,插入次数+1并把map清零,记录当前位置的值到map里。

#include<bits/stdc++.h>
#define ll long long
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;int32_t main()
{IOS;ll n,sum=0,ans=0;cin>>n;map<ll,bool>M;//M[x]记录前缀合x是否在前面出现过,如果当前前缀和为x,那么在当前位置到之前记录x的位置之间的数加起来为0M[0]=1;//0要初始化为出现过,意思为开头到目前为止所有部分的值加起来为0for(int i=0;i<n;i++){ll x;cin>>x;sum+=x;if(M.find(sum)!=M.end())//如果当前前缀和和之前某个位置的相同,代表这两个位置间(包括当前位置)的值加起来为0{//贪心过程在当前位置前的一个位置塞入一个绝对值足够大的数字即可M.clear();sum=x;//当前前缀合变为刚读入的这个数,前面的数字不再对后续产生影响,可以理解为我们在前面一个位置插入了一个无穷大M[x]=M[0]=1;ans++;}else M[sum]=1;}cout<<ans<<endl;
}

E题
贪心,小结论,暴力

两个人进行n轮石头剪刀布,每个人准备出几次剪刀,几次石头,几次布都已经给出,要求求出第一个人最少和最多能获得的胜场数。

最多能获得的胜场数很容易贪心得到,直接第一个人的剪刀和第二个人的布的场次取较小值加到答案上,另外两种情况也相同。

最少能获得的胜场数需要做个小结论,我们可以反过来思考,我们要获得最少的胜场数,也就等同于要得到最多的平局和负场数。而平局和负场的话,剪刀可以与剪刀构成平局,也可以去和石头构成负场。
我们优先考虑平局,再在这里我人为规定一个词叫做“被挤占”的状态,比如说1次第一个人的剪刀我们安排和第二个人的石头对应,1次第一个人的石头本来应当和第二个人的石头对应,现在“被挤占”后被迫和布对应。
如果剪刀石头布都存在“被挤占”的状态的话,不难发现构成了一个三场都负的循环,我们完全可以让他们变成三场都平局,排除这三个“被挤占”的状态。从而可以得到结论,最优的那种情况,必然可以转化为剪刀石头布中有一个不存在“被挤占”状态的方案,也就是优先考虑三种出法某一种。
由此我们直接for个3遍,优先考虑三种出法能获得的平局和负场数,取最大后被减去便是答案。

#include<bits/stdc++.h>
#define ll long long
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;ll a[3],b[3];int32_t main()
{IOS;ll n;cin>>n;cin>>a[0]>>a[1]>>a[2];cin>>b[0]>>b[1]>>b[2];ll ans=0;//记录最高可以得到的负场和平局数量for(int i=0;i<3;i++)//优先考虑a中的哪一个{ll now=0,sum=0;//now记录位置有多少场次需要寻找平局和负场,sum为优先考虑a[i]的情况下得到的负场和平局数for(int j=0;j<3;j++){int tar=(i-j+3)%3;//寻找当前位置的下标,现在是尽可能多的寻找平局和负场ll temp=b[tar];sum+=min(now,temp);temp-=min(now,temp);//上一个位置留下的部分可以在当前位置放now=a[tar];//放置后上一个位置的场次没被安排的无法保存到下一个,直接清零记录为当前位置的场次即可sum+=min(now,temp);now-=min(now,temp);//当前位置b仍然能安排的优先安排}ans=max(ans,sum);}cout<<n-ans<<' ';ans=0;for(int i=0;i<3;i++) ans+=min(a[i],b[(i+1)%3]);cout<<ans<<endl;
}

F题
dp

题意为给定一个字符串,只包含abc?四种字符,其中?字符可以用abc任意一个去替换,问将所有的?替换后的所有字符串中,子串abc(下标不一定连续)总共出现了几次。

我们注意到,我们如果从左往右看过去的话,我们实际上需要关注的,只是a,ab,abc出现了几次。那么我们可以根据第i个位置是a,b,c做一个3 × \times × n 的线性dp。
首先当前位置的情况,要继承上个位置所有构造方案的情况(见trans函数)。之后根据当前位置构造是a还是b还是c进行三种不同的转换。
如果构造a的话,只会对a的数量产生影响,当前位置之前出现了x个问号,那么此时前面共有3x种构造方法,每种方法都会增加一个a。因此直接增加3x个a。
如果构造b的话,只会对ab的数量产生影响,增加前面一个位置下记录的所有a的个数即可。
如果构造c的话,只会对abc的数量产生影响,增加前面一个位置下记录的所有ab的个数即可。

#include<bits/stdc++.h>
#define ll long long
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;
const ll mod=1e9+7;
const ll maxn=2e5+7;struct Node
{ll a,ab,abc;
};Node dp[maxn][3];//dp[i][j]表示第i个字符构造j的情况下,a/ab/abc各自出现了几次,j=0代表构造字符'a',j=1代表构造'b',j=2代表构造'c'
//当s[i]是个确定的字符时,只转移到dp[i][0]上
int n;
ll cas=1;//记录3^k,用于构造'a'时的转移
char s[maxn];void trans(int x,int y)
{for(int i=0;i<3;i++){dp[x][y].a=(dp[x][y].a+dp[x-1][i].a)%mod;dp[x][y].ab=(dp[x][y].ab+dp[x-1][i].ab)%mod;dp[x][y].abc=(dp[x][y].abc+dp[x-1][i].abc)%mod;}
}void transa(int x,int y)//构造a时的转移方式
{trans(x,y);dp[x][y].a=(dp[x][y].a+cas)%mod;
}void transb(int x,int y)//构造b时的转移方式
{trans(x,y);dp[x][y].ab=(dp[x][y].ab+dp[x-1][0].a+dp[x-1][1].a+dp[x-1][2].a)%mod;
}void transc(int x,int y)//构造c时的转移方式
{trans(x,y);dp[x][y].abc=(dp[x][y].abc+dp[x-1][0].ab+dp[x-1][1].ab+dp[x-1][2].ab)%mod;
}int32_t main()
{IOS;cin>>n>>(s+1);for(int i=1;i<=n;i++){if(s[i]=='?'){transa(i,0);transb(i,1);transc(i,2);cas=cas*3%mod;}else{if(s[i]=='a') transa(i,0);if(s[i]=='b') transb(i,0);if(s[i]=='c') transc(i,0);}}cout<<(dp[n][0].abc+dp[n][1].abc+dp[n][2].abc)%mod<<endl;
}

这篇关于Codeforces Round #674 (Div. 3)A-F题解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/664705

相关文章

Codeforces Round #240 (Div. 2) E分治算法探究1

Codeforces Round #240 (Div. 2) E  http://codeforces.com/contest/415/problem/E 2^n个数,每次操作将其分成2^q份,对于每一份内部的数进行翻转(逆序),每次操作完后输出操作后新序列的逆序对数。 图一:  划分子问题。 图二: 分而治之,=>  合并 。 图三: 回溯:

Codeforces Round #261 (Div. 2)小记

A  XX注意最后输出满足条件,我也不知道为什么写的这么长。 #define X first#define Y secondvector<pair<int , int> > a ;int can(pair<int , int> c){return -1000 <= c.X && c.X <= 1000&& -1000 <= c.Y && c.Y <= 1000 ;}int m

Codeforces Beta Round #47 C凸包 (最终写法)

题意慢慢看。 typedef long long LL ;int cmp(double x){if(fabs(x) < 1e-8) return 0 ;return x > 0 ? 1 : -1 ;}struct point{double x , y ;point(){}point(double _x , double _y):x(_x) , y(_y){}point op

Codeforces Round #113 (Div. 2) B 判断多边形是否在凸包内

题目点击打开链接 凸多边形A, 多边形B, 判断B是否严格在A内。  注意AB有重点 。  将A,B上的点合在一起求凸包,如果凸包上的点是B的某个点,则B肯定不在A内。 或者说B上的某点在凸包的边上则也说明B不严格在A里面。 这个处理有个巧妙的方法,只需在求凸包的时候, <=  改成< 也就是说凸包一条边上的所有点都重复点都记录在凸包里面了。 另外不能去重点。 int

C++ | Leetcode C++题解之第393题UTF-8编码验证

题目: 题解: class Solution {public:static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num &

Codeforces 482B 线段树

求是否存在这样的n个数; m次操作,每次操作就是三个数 l ,r,val          a[l] & a[l+1] &......&a[r] = val 就是区间l---r上的与的值为val 。 也就是意味着区间[L , R] 每个数要执行 | val 操作  最后判断  a[l] & a[l+1] &......&a[r] 是否= val import ja

C语言 | Leetcode C语言题解之第393题UTF-8编码验证

题目: 题解: static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num & MASK1) == 0) {return

C - Word Ladder题解

C - Word Ladder 题解 解题思路: 先输入两个字符串S 和t 然后在S和T中寻找有多少个字符不同的个数(也就是需要变换多少次) 开始替换时: tips: 字符串下标以0开始 我们定义两个变量a和b,用于记录当前遍历到的字符 首先是判断:如果这时a已经==b了,那么就跳过,不用管; 如果a大于b的话:那么我们就让s中的第i项替换成b,接着就直接输出S就行了。 这样

CSS实现DIV三角形

本文内容收集来自网络 #triangle-up {width: 0;height: 0;border-left: 50px solid transparent;border-right: 50px solid transparent;border-bottom: 100px solid red;} #triangle-down {width: 0;height: 0;bor

【秋招笔试】9.07米哈游秋招改编题-三语言题解

🍭 大家好这里是 春秋招笔试突围,一起备战大厂笔试 💻 ACM金牌团队🏅️ | 多次AK大厂笔试 | 大厂实习经历 ✨ 本系列打算持续跟新 春秋招笔试题 👏 感谢大家的订阅➕ 和 喜欢💗 和 手里的小花花🌸 ✨ 笔试合集传送们 -> 🧷春秋招笔试合集 🍒 本专栏已收集 100+ 套笔试题,笔试真题 会在第一时间跟新 🍄 题面描述等均已改编,如果和你笔试题看到的题面描述