Dashboard - Codeforces Round #676 (Div. 2) - Codeforces
A. XORwice
题意:给你俩个数a,b,问的最小值,x可以任意取值(为异或)
知识点:位运算,思维
思路:设答案为ans
我们可以先把a和b都拆成二进制后每一位考虑,
如果某一位上a和b都是1,那么x在这一位上一定是1,ans在这一位上是0
如果某一位上a和b其中一个是1,x在这一位上可以是0或者1,ans在这一位上是1
如果某一位上a和b都是0,那么x在这一位上一定是0,ans在这一位上是0
可以容易发现ans=
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 2e5+5;
const ll mod =1e9+7;
void solve(){
ll a,b;cin>>a>>b;
cout<<(a^b)<<'\n';
}
int main() {
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
int _=1;cin>>_;
while(_--){
solve();
}
return 0;
}
B. Putting Bricks in the Wall
题意:给你一个的地图,地图上除了和每个点为0或者1,现在明明想从走到,他会在开始时随机选择1或者0来走,之后他可以在他选择的数字的格子上任意跳着走,和是只能上下左右走一格,现在你可以修改最多2次,把0变成1,或者1变成0,问能不能让明明不管选什么数字都不能从走到。
知识点:思维,读题(不是
思路:只要开始旁边的两个格子和结束旁边的两个格子完全不同就行了,这样不管怎么样都是不互通的,而且一定存在一个小于等于2的修改次数的答案,我们可以直接二进制枚举这4个格子的每一种状况,然后判断出来一个符合的就行了。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 2e5+5;
const ll mod =1e9+7;
char mp[205][205];
ll n;
pair<ll,ll>w[4];
char pre[4];
bool check(){
ll cnt=0;
for(int i=0;i<2;++i){
ll rp=mp[w[i].first][w[i].second]-'0';
for(int j=2;j<4;++j){
ll wp=mp[w[j].first][w[j].second]-'0';
if(rp^wp==1)cnt++;
}
}
return cnt==4;
}
void solve(){
cin>>n;
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
cin>>mp[i][j];
}
}
w[0]={1,2};w[1]={2,1}; //开始旁边的两个格子下标
w[2]={n,n-1};w[3]={n-1,n};//结束旁边的两个格子下标
pre[0]=mp[1][2];pre[1]=mp[2][1]; //开始旁边的两个格子的数字
pre[2]=mp[n][n-1];pre[3]=mp[n-1][n];//结束旁边的两个格子的数字
for(int i=0;i<(1<<4);++i){//二进制枚举
for(int j=0;j<4;++j){
if(i&(1<<j))mp[w[j].first][w[j].second]='1';
else mp[w[j].first][w[j].second]='0';
}
if(check()){//如果开始旁边两个格子和结束旁边两个格子完全不同
vector<pair<ll,ll> >ans;
for(int j=0;j<4;++j){
if(mp[w[j].first][w[j].second]==pre[j])continue;
ans.push_back(w[j]);//修改了
}
if(ans.size()>2)continue;//修改次数不符合条件
cout<<ans.size()<<'\n';
for(auto [x,y]:ans)cout<<x<<' '<<y<<'\n';
return ;
}
}
}
int main() {
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
int _=1;cin>>_;
while(_--){
solve();
}
return 0;
}
C. Palindromifier
题意:给你一个字符串s,有两个操作
设n为当前字符串长度
操作1:选择一个,,然后把反转拼接到s前面
操作2:选择一个,,然后把反转拼接到s后面
现在你要在30次操作之内,把字符串s变成回文串
知识点:构造,思维
思路:可以发现这俩操作其实就是以左,右端点为中心,补全一个回文
可以发现,如果我有ab,我可以凑出aba反转后是ba,我依旧可以凑出aba
所以我要把反转的字符串中的边界有一个回文中心+半径的所有字符
这样就可以把整个字符串弄成回文,具体步骤如下
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 2e5+5;
const ll mod =1e9+7;
void solve(){
string s;cin>>s;
ll l=s.length();
cout<<3<<'\n';
cout<<'R'<<' '<<l-1<<'\n';
cout<<'L'<<' '<<l<<'\n';
cout<<'L'<<' '<<2<<'\n';
}
int main() {
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
int _=1;//cin>>_;
while(_--){
solve();
}
return 0;
}
D. Hexagons
题意:在一个二维平面上,我可以走上,下,左,右,右上,左下,6个方向走一步的代价分别为,现在给出一个坐标,问从走到的最小代价。
知识点:分类讨论,数学
思路:我们可以先讨论出上,下,左,右,左上,左下,右上,右下,8个方向走一步的代价的最小值,比如左上=min 左 + 上,左下+2*上,右上+2*左这样依次讨论出
然后对于一个4个区域来说,每个区域情况都一样,只不过代价的下标不同,我这里只给出右上半区的情况
如果y>x,就是红(上y+右x),绿(右上x+上(y-x)),粉(右上y+左(y-x))三种情况
其他,就是棕(右上y+右(y-x)),黄绿(右上x+下(y-x)),紫(上y+右x)三种情况
剩下三个区域也是相同的
然后码代码就行了
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 2e5+5;
const ll mod =1e9+7;
ll c[7],dp[9];
void solve(){
ll x,y;cin>>x>>y;
ll tx=abs(x),ty=abs(y);
for(int i=1;i<=6;++i)cin>>c[i];
dp[1]=min(c[2],c[1]+c[3]);//上
dp[2]=min(c[5],c[4]+c[6]);//下
dp[3]=min(c[3],c[4]+c[2]);//左
dp[4]=min(c[6],c[1]+c[5]);//右
dp[5]=min({c[3]+c[2],c[4]+2*c[2],c[1]+2*c[3]});//左上
dp[6]=min(c[4],c[5]+c[3]);//左下
dp[7]=min(c[1],c[2]+c[6]);//右上
dp[8]=min({c[5]+c[6],c[4]+2*c[6],c[1]+2*c[5]});//右下
ll ans=2e18;//一定要比2e18大
if(x>=0&&y>=0){//右上半区
ans=min(ans,ty*dp[1]+tx*dp[4]);
if(tx>ty){
ans=min(ans,ty*dp[7]+(tx-ty)*dp[4]);
ans=min(ans,tx*dp[7]+(tx-ty)*dp[2]);
}
else {
ans=min(ans,tx*dp[7]+(ty-tx)*dp[1]);
ans=min(ans,ty*dp[7]+(ty-tx)*dp[3]);
}
}
else if(x>=0&&y<=0){//右下半区
ans=min(ans,ty*dp[2]+tx*dp[4]);
if(tx>ty){
ans=min(ans,ty*dp[8]+(tx-ty)*dp[4]);
ans=min(ans,tx*dp[8]+(tx-ty)*dp[1]);
}
else {
ans=min(ans,tx*dp[8]+(ty-tx)*dp[2]);
ans=min(ans,ty*dp[8]+(ty-tx)*dp[3]);
}
}
else if(x<=0&&y>=0){//左上半区
ans=min(ans,ty*dp[1]+tx*dp[3]);
if(tx>ty){
ans=min(ans,ty*dp[5]+(tx-ty)*dp[3]);
ans=min(ans,tx*dp[5]+(tx-ty)*dp[2]);
}
else {
ans=min(ans,tx*dp[5]+(ty-tx)*dp[1]);
ans=min(ans,ty*dp[5]+(ty-tx)*dp[4]);
}
}
else {//左下半区
ans=min(ans,ty*dp[2]+tx*dp[3]);
if(tx>ty){
ans=min(ans,ty*dp[6]+(tx-ty)*dp[3]);
ans=min(ans,tx*dp[6]+(tx-ty)*dp[1]);
}
else {
ans=min(ans,tx*dp[6]+(ty-tx)*dp[2]);
ans=min(ans,ty*dp[6]+(ty-tx)*dp[4]);
}
}
cout<<ans<<'\n';
}
int main() {
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
int _=1;cin>>_;
while(_--){
solve();
}
return 0;
}
E. Swedish Heroes
题意:有一个长度为n的数组a,现在有一个操作,每次选出数组中相邻俩个数变成,再放回原数组,问经过n-1次操作后,剩下一个数字的最大值
知识点:思维,DP
思路:其实最后答案ans=,我们设cnt1为op[i]=1的数量,cnt2为op[i]=-1的数量,然后这题有个结论,也就是(菜鸡看不出来orz),
然后就是有一个特例不符合条件,就比如 op数组是 1 -1 1 -1 1,也满足刚刚那个结论,但是他不可能出现,因为在开始的第一次操作中一定会让某两个相邻的op是相同的,剩下操作也不会让开始这俩变成不同,所以,除了要满足上述结论,还要满足至少存在某两个相邻的op是相同的
知道这个结论后就可以DP了,设DP[i][0/1/2][0/1]表示前i个数,对3取模后cnt2个数为0/1/2,是否满足条件二的最大答案
初始条件 dp[1][0][0]=a[1],dp[1][1][1]=-a[1]
转移 我们奇偶分开,
i奇数,dp[i][j][0]=dp[i-1][j][0]+a[i];//+一下
dp[i][j][1]=dp[i-1][(j+2)%3][0]-a[i];//上一位是-,这里也-就满足了条件二
i偶数,dp[i][j][0]=dp[i-1][(j+2)%3][0]-a[i];//-一下
dp[i][j][1]=dp[i-1][j][0]+a[i];//上一位是+,这里也+就满足了条件二
然后,dp[i][j][1]=max dp[i][j][1],dp[i-1][j][1]+a[i],dp[i-1][(j+2)%3][1]-a[i]//符合条件二的转移
最后答案就是符合的dp[n][i][1],注意n=1的特判和dp的初始化
ops:
dp[i][0/1/2][0]相当于求了一个op=1 -1 1 -1 1这样的答案
dp[i][0/1/2][1]相当于在上面的基础上变化其中几个op的符合的最大值
初始一定是1 -1 1 -1... 而不是-1 1 -1 1....因为-1开头一定不可能构成条件一的
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 2e5+5;
const ll mod =1e9+7;
ll n,a[N];
ll dp[N][3][2];
void solve(){
cin>>n;
for(int i=1;i<=n;++i){
cin>>a[i];
for(int j=0;j<3;++j){
dp[i][j][0]=dp[i][j][1]=-1e18;//初始化
}
}
if(n==1){//特判
cout<<a[1]<<'\n';
return ;
}
dp[1][0][0]=a[1];
dp[1][1][1]=-a[1];
for(int i=2;i<=n;++i){
for(int j=0;j<3;++j){
if(i&1){//奇数转移
dp[i][j][0]=dp[i-1][j][0]+a[i];
dp[i][j][1]=dp[i-1][(j+2)%3][0]-a[i];
}
else {//偶数转移
dp[i][j][0]=dp[i-1][(j+2)%3][0]-a[i];
dp[i][j][1]=dp[i-1][j][0]+a[i];
}
//符合条件二的转移
dp[i][j][1]=max({dp[i][j][1],dp[i-1][j][1]+a[i],dp[i-1][(j+2)%3][1]-a[i]});
}
}
for(int i=0;i<3;++i){
if((n+i)%3==1){//定位答案位置
cout<<dp[n][i][1]<<'\n';
return ;
}
}
}
int main() {
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
int _=1;//cin>>_;
while(_--){
solve();
}
return 0;
}