Codeforces #668 div2
比赛链接
https://codeforces.ml/contest/1405
A. Permutation Forgery
题目大意
给你一个1~n的排列,然后用数组中每两个相邻元素的和构成一个新的数组,对其进行排序得到数组c。让你找出一个与给出的排列不同的排列,让其进行以上相同操作后得到的数组c2与c相同。
解题思路
首先思考要让排序过后的两个数组c和c2相等,那么就是让两个数组中的元素相等。而c中每个元素是给定排列的相邻元素之和,则我们只要逆转给定排序,即可满足条件。
AC代码
#include<bits/stdc++.h>
#define MAXN 3000005
using namespace std;
int a[MAXN];
void solve()
{
int n;cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=n;i>=1;i--)
cout<<a[i]<<' ';
cout<<endl;
}
int main()
{
int T;cin>>T;
while(T--)
solve();
}
B. Array Cancellation
题目大意
给定一个数组a,且所有元素和为0。每次操作可以选定一组(i,j)增加 a[i]的值,同时 a[j] 减去相同大小的值,最后让所有元素的值都为0。若 i < j 则无开销,反之开销为增减的值大小。问最小开销是多少。
解题思路
题目中给出 i < j 的时候增减是没有开销的,因此贪心选择 尽量使得每个每个靠前的正数能给把数值分配给他后面的负数。当没法分配的时候残余的值就不得不往前分配,便是最小开销。
AC代码
#include<bits/stdc++.h>
#define MAXN 3000005
using namespace std;
long long a[MAXN];
void solve()
{
int n;cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
long long premix=0;
for(int i=1;i<=n;i++)
{
if(a[i]>0)
premix+=a[i];
if(a[i]<0&&premix>0)
premix=max(0LL,premix+a[i]);
}
cout<<premix<<endl;
}
int main()
{
int T;cin>>T;
while(T--)
solve();
}
C. Balanced Bitstring
题目大意
给你一个01串 s 和一个偶数k,01串内的?可以变成0或者1,问你是否可以让该串每个长度为k的子串里0和1的数量相等。
解题思路
通过观察发现,s[i] 和 s[i+k] 应该是相同的 因为当区间从s[i]-s[i+k-1]转移到 s[i+1]-s[i+k] 的时候,我们减去了s[i],所以要让区间里的0和1仍然平衡,则加上的s[i+k]必然等于s[i]。我们只需要判断能否满足这个条件即可。
AC代码
#include<bits/stdc++.h>
#define MAXN 3000005
using namespace std;
long long a[MAXN];
void solve()
{
int n,k;cin>>n>>k;int a=0,b=0,c=0;
string s;cin>>s;int flag=1;
for(int i=k;i<s.size();i++)
{
if(s[i]!=s[i%k])
{
if(s[i%k]=='?')
s[i%k]=s[i];
else if(s[i%k]!='?'&&s[i]!='?')
goto Tag;
}
}
for(int i=0;i<k;i++)
{
if(s[i]=='1')
a++;
else if(s[i]=='0')
b++;
else
c++;
}
if(abs(a-b)>c)
goto Tag;
else
cout<<"YES"<<endl;
return;
Tag:
cout<<"NO"<<endl;
}
int main()
{
int T;cin>>T;
while(T--)
solve();
}
D. Tree Tag
题目大意
Alice和Bob都在一棵树上,起始点为a和b,且Alice要去抓Bob。Alice每步可以走最多da步,Bob每次最多可以走db步,且Alice和Bob轮流走,问Alice能不能抓住Bob。(Alice走完一次落在Bob所在的节点上)
解题思路
先观察数据,我们发现第二个数据是一条链,而Bob可以在Alice的左右两边反复横跳,让Alice无法追上。于是我们想,是不是能在树上找到一条这样的链,达到这样的效果。由于树的直径是树上最长的一条链,我们可以求出树的直径结合Alice和Bob可以跳的步数判断是否可以达成如上效果。应满足的条件有:
da*2 < min(db, 直径) (Bob可以跳的距离足够长,以至于能在Alice的左右两边左右横跳而不被追上。
dist(a,b)>da (由于第一轮是Alice,如果b和a的距离小于da,则Alice可以直接抓住Bob)
AC代码
#include<bits/stdc++.h>
#define MAXN 3000005
using namespace std;
struct EDGE
{
int to,next;
}edge[MAXN];int ptr;
int head[MAXN];
void add_edge(int from,int to)
{
edge[++ptr].to=to;
edge[ptr].next=head[from];
head[from]=ptr;
}
//求树的深度
int depth[MAXN];
void dfs(int now,int f)
{
depth[now]=depth[f]+1;
for(int p=head[now];p;p=edge[p].next)
{
int to=edge[p].to;
if(to!=f)dfs(to,now);
}
}
void init(int n)
{
ptr=0;
for(int i=1;i<=n;i++)
head[i]=edge[i].to=edge[i].next=depth[i]=0;
}
//求a和b的距离
int dist(int a,int b)
{
dfs(a,0);
return depth[b]-1;
}
void solve()
{
int n,a,b,da,db;cin>>n>>a>>b>>da>>db;
init(n);
for(int i=1;i<n;i++)
{
int u,v;cin>>u>>v;
add_edge(u,v);
add_edge(v,u);
}
//求树的直径
dfs(1,0);int maxx=0,root=0;
for(int i=1;i<=n;i++)
if(depth[i]>maxx)
maxx=depth[i],root=i;
dfs(root,0);maxx=0;
for(int i=1;i<=n;i++)
maxx=max(maxx,depth[i]); //maxx是树的直径+1
if(maxx-1>2*da&&da*2<db&&dist(a,b)>da)
cout<<"Bob"<<endl;
else
cout<<"Alice"<<endl;
}
int main()
{
int T;cin>>T;
while(T--)
solve();
}