codeforces 1296 题解(完结)
codeforces 1296 题解
A. Array with Odd Sum
想要数组加和为奇数,可以从数组长度是奇数还是偶数着手
- 若数组长度为偶数,则数组全奇或全偶必定不能构造满足题目要求的数列
- 若数组长度为奇数,则数组全偶必定不能构造满足题目要求的数列
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
#define _for(i,a,b) for(int i = (a);i < b;i ++)
#define _rep(i,a,b) for(int i = (a);i > b;i --)
#define INF 0x3f3f3f3f
#define ZHUO 11100000007
#define MOD 1000000007
#define MIKUNUM 39
#define pb push_back
#define debug() printf("Miku Check OK!\n")
#define maxn 3503
#define X first
#define Y second
int main()
{
ios::sync_with_stdio(false);
int t;
cin >> t;
while(t--)
{
int n;
cin >> n;
//全て odd と even
int subedeodd = 1,subedeeven = 1;
_for(i,0,n)
{
int tmp;
cin >> tmp;
if(tmp&0x1)
subedeeven = 0;
else
subedeodd = 0;
}
if( ((!(n&0x1))&&(subedeeven||subedeodd))
|| ((n&0x1) && subedeeven))
printf("NO\n");
else
printf("YES\n");
}
return 0;
}
B. Food Buying
原谅我不懂 \(cashback\) 的含义...但从题目理解去模拟即可,每次得到的钱再加上去然后再滚一遍
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
#define _for(i,a,b) for(int i = (a);i < b;i ++)
#define _rep(i,a,b) for(int i = (a);i > b;i --)
#define INF 0x3f3f3f3f
#define ZHUO 11100000007
#define MOD 1000000007
#define MIKUNUM 39
#define pb push_back
#define debug() printf("Miku Check OK!\n")
#define maxn 3503
#define X first
#define Y second
int main()
{
ios::sync_with_stdio(false);
int t;
cin >> t;
while(t--)
{
int x;
cin >> x;
int rnt = 0;
while(x>=10)
{
int tmp = x-x%10;
rnt += tmp;
x -= tmp;
x += tmp/10;
}
printf("%d\n",rnt+x);
}
return 0;
}
C. Yet Another Walking Robot
题目说的挺花哨,翻译翻译,把问题转化一下,就是在字符串中找一最小子串使得能够恰好抵消。什么叫恰好抵消?\(L\) 能和 \(R\) 抵消,\(U\) 能和 \(D\) 抵消,也就是字符串里 \(L\) 和 \(R\) 的数量相等, \(U\) 和 \(D\) 数量相等即可。
光从字符串角度想不好想,我们考虑一下这个机器人怎么算是能恰好抵消——很显然,如果这个机器人走到了之前走到的位置,也就是它绕了个圈,那就是能够恰好抵消,这个圈就是我们应该删掉的部分。
记录当前位置,存到 \(map\) 里,\(first\) 记录到过的坐标,\(second\) 记录在哪儿到过的,每次到达的位置就去 \(map\) 里找找,能找到说明有个圈,看看能不能更新答案,然后把这个圈的碰撞点的 \(second\) 更新为当前位置。
时间复杂度 \(O(nlogn)\)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
#define _for(i,a,b) for(int i = (a);i < b;i ++)
#define _rep(i,a,b) for(int i = (a);i > b;i --)
#define INF 0x3f3f3f3f
#define ZHUO 11100000007
#define MOD 1000000007
#define MIKUNUM 39
#define pb push_back
#define debug() printf("Miku Check OK!\n")
#define maxn 3503
#define X first
#define Y second
int main()
{
ios::sync_with_stdio(false);
int t;
cin >> t;
while(t--)
{
int n;
string s;
cin >> n >> s;
map<pair<int,int>,int> mp;
int ans = INF;
int anst,aned;
int x = 0, y = 0;
mp[{0,0}] = -1;
_for(i,0,s.size())
{
if(s[i]=='L')
x --;
else if(s[i]=='R')
x ++;
else if(s[i]=='U')
y ++;
else
y --;
auto iter = mp.find({x,y});
if(iter!=mp.end() && ans > i-iter->second)
{
ans = i-iter->second;
anst = iter->second+2;
aned = i+1;
}
mp[{x,y}] = i;
}
if(ans==INF)
printf("-1\n");
else
printf("%d %d\n",anst,aned);
}
return 0;
}
D. Fight with Monsters
读题后注意到,虽然是顺序打怪,但是其实你可以任意挑选怪物来打,因为最后算的是总得分,怪物也不会还手你和你的对手可以一起打下去。因为每一只怪物得到的分数都是平等的,那不妨统计一下每只怪物需要你让你的对手停手几次你才能把这只怪物搞定。因为是回合制所以一开始你们可以混合双打,把怪物打到 只要你来一下,你的对手来一下,怪物就必死 的状态,然后你看看你能不能来一下直接把怪物秒了,不能的话那就得让你的对手停手然后你再来一下... ...直到怪物被杀死为止。
然后你得到一个数组,就是每个怪物需要你的对手停手几次才能打死。对这个数组从小到大排序,然后从前往后看看能搞定几个怪物即可。
时间复杂度 \(O(nlogn)\)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
#define _for(i,a,b) for(int i = (a);i < b;i ++)
#define _rep(i,a,b) for(int i = (a);i > b;i --)
#define INF 0x3f3f3f3f
#define ZHUO 11100000007
#define MOD 1000000007
#define MIKUNUM 39
#define pb push_back
#define debug() printf("Miku Check OK!\n")
#define maxn 200039
#define X first
#define Y second
int n, a, b, k;
int h[maxn];
int main()
{
ios::sync_with_stdio(false);
cin >> n >> a >> b >> k;
_for(i,1,n+1)
{
cin >> h[i];
int t1 = h[i]/(a+b);
h[i] -= max(0,t1-1)*(a+b);
if(h[i]>(a+b))
h[i] -= a+b;
int t3 = h[i]/a;
if(a>=h[i] || !(h[i]%a))
h[i] = max(0,t3-1);
else
h[i] = t3;
}
sort(h+1,h+1+n);
int rnt = 0;
for(int i = 1;i <= n && k >= h[i];i ++)
{
k -= h[i];
rnt ++;
}
printf("%d\n",rnt);
return 0;
}
E. String Coloring
不同颜色相邻可互换,意思就是相同颜色相对位置保持稳定,为什么?举个例子,\(1010\) ,其中第二个 \(0\) 永远不可能跑到第一个 \(0\) 前面,因为当两个 \(0\) 紧挨着的时候他们是不能互换的。
如果相同颜色相对位置保持稳定,最后需要一个整体有序的字符串,那就需要相同颜色先要有序,则最后经过调换整体才会有序。因此 不管是简单版本还是困难版本的任务就都变成了:字符串最少有几串整体有序的子串。
因为每一个字符都会被分配一个颜色,所以我们可以遍历原字符串,对于当前字符,我们考虑将他填入第一种颜色,不行的话我们就填第二种颜色... ...如果都不行,我们就只能给他全新开创一种颜色,可以证明这样填颜色,需要的颜色数量是最少的。
时间复杂度为 \(O(26n)=O(n)\)
简单版本:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
#define _for(i,a,b) for(int i = (a);i < b;i ++)
#define _rep(i,a,b) for(int i = (a);i > b;i --)
#define INF 0x3f3f3f3f
#define ZHUO 11100000007
#define MOD 1000000007
#define MIKUNUM 39
#define pb push_back
#define debug() printf("Miku Check OK!\n")
#define maxn 200039
#define X first
#define Y second
int n;
string s;
char last[30];
int ans[maxn];
int cnt = 0;
int main()
{
ios::sync_with_stdio(false);
cin >> n >> s;
ans[0] = cnt;
last[cnt++] = s[0];
_for(i,1,n)
{
int flag = 0;
_for(j,0,cnt)
{
if(s[i]>=last[j])
{
last[j] = s[i],ans[i] = j,flag = 1;
break;
}
}
if(!flag)
{
ans[i] = cnt;
last[cnt++] = s[i];
}
}
int flag = 1;
_for(i,0,n)
if(ans[i]>1)
flag = 0;
if(!flag)
printf("NO");
else
{
printf("YES\n");
_for(i,0,n)
printf("%d",ans[i]);
}
return 0;
}
困难版本
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
#define _for(i,a,b) for(int i = (a);i < b;i ++)
#define _rep(i,a,b) for(int i = (a);i > b;i --)
#define INF 0x3f3f3f3f
#define ZHUO 11100000007
#define MOD 1000000007
#define MIKUNUM 39
#define pb push_back
#define debug() printf("Miku Check OK!\n")
#define maxn 200039
#define X first
#define Y second
int n;
string s;
char last[30];
int ans[maxn];
int cnt = 0;
int main()
{
ios::sync_with_stdio(false);
cin >> n >> s;
ans[0] = cnt;
last[cnt++] = s[0];
_for(i,1,n)
{
int flag = 0;
_for(j,0,cnt)
{
if(s[i]>=last[j])
{
last[j] = s[i],ans[i] = j,flag = 1;
break;
}
}
if(!flag)
{
ans[i] = cnt;
last[cnt++] = s[i];
}
}
int maxium = 0;
_for(i,0,n)
maxium = max(maxium,ans[i]+1);
printf("%d\n",maxium);
_for(i,0,n)
printf("%d ",ans[i]+1);
return 0;
}
F. Berland Beauty
给你一些两点间最小的边权条件,让你找到一组边权满足题意。那我们可以把所有要填的边以边权从大到小排一下,然后直接把两点间的边权都默认为该边权。因为这样后填的可以 “容忍” 前面填的,因为前面填的一定更大,当然了,如果填过自然就不填。就这样填完一遍以后,再根据每个条件遍历一遍,看看这条路上最小的边权是不是就是满足这个条件的,不满足自然 \(-1\) 咯。
注意,所有边权不一定通过第一遍填就能填满,如果填完一遍以后该边还是处于没填的状态,那这条边随便填什么都能满足条件,因为根本没有条件涉及到他。哈?你问我填什么数字?那我自然是填代表 \(Miku\) 的 \(39\) 啦!
时间复杂度 \(O(n^2)\)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
#define _for(i,a,b) for(int i = (a);i < b;i ++)
#define _rep(i,a,b) for(int i = (a);i > b;i --)
#define INF 0x3f3f3f3f
#define ZHUO 11100000007
#define MOD 1000000007
#define MIKUNUM 39
#define pb push_back
#define debug() printf("Miku Check OK!\n")
#define maxn 10039
#define maxe 100039
#define X first
#define Y second
struct G
{
int n,m;
int Next[maxe];
int head[maxn];
int ver[maxe];
int val[maxe];
int tot;
void add(int x,int y,int w)
{
ver[++tot] = y,Next[tot] = head[x],head[x] = tot,val[tot] = w;
}
} g;
struct q
{
int st;
int ed;
int w;
bool operator < (q b)
{
return w > b.w;
}
};
int k;
q ask[maxn];
int flag = INF;
bool dfs(int x, int goal, int fa, int w)
{
if(x==goal)
return true;
for(int i = g.head[x]; i; i = g.Next[i])
{
int y = g.ver[i];
if(y==fa)
continue;
if(dfs(y,goal,x,w))
{
if(g.val[i]==-1)
g.val[i] = g.val[i^1] = w;
return true;
}
}
return false;
}
bool check(int x, int goal, int fa)
{
if(x==goal)
return true;
for(int i = g.head[x]; i; i = g.Next[i])
{
int y = g.ver[i];
if(y==fa)
continue;
if(check(y,goal,x))
{
flag = min(flag,g.val[i]);
return true;
}
}
return false;
}
int main()
{
ios::sync_with_stdio(false);
cin >> g.n;
g.m = g.n-1;
g.tot = 1;
_for(i,0,g.m)
{
int x, y;
cin >> x >> y;
g.add(x,y,-1),g.add(y,x,-1);
}
cin >> k;
_for(i,0,k)
cin >> ask[i].st >> ask[i].ed >> ask[i].w;
sort(ask,ask+k);
_for(i,0,k)
dfs(ask[i].st, ask[i].ed, -1, ask[i].w);
_for(i,0,k)
{
check(ask[i].st, ask[i].ed, -1);
if(flag != ask[i].w)
{
flag = 0;
break;
}
flag = INF;
}
if(!flag)
printf("-1\n");
else
{
for(int i = 2;i < g.m*2+2;i += 2)
printf("%d ",g.val[i]==-1?39:g.val[i]);
}
return 0;
}