Atcoder Beginner Contest D题 选解

闲着没事干,在vjudge上面vpABC的D题.
这些题目大多数思路都非常妙,让我不禁眼前一亮.

过程

我与Styx大佬同时开始vp,大家都没有看过题.
一开始我们看哪题哪题不会.
但是5个小时之后我们都AK了,还意犹未尽,觉得4题不够,表示再加一题.(涂掉)

A

石头剪刀布,你与对面都只能出石头和布.
任何时候你与对面都必须保证出的石头的数量严格大于或者等于出的布的次数.
你赢一轮得1分,输一轮-1分.给出对面的出招序列,求你能获得的最大分数.

一开始考虑dp.但是这个数据范围不允许.
我开始向贪心方向考虑.首先最优解中出布的次数必然有一半.
想了半天发现了让我自己都震惊的结论:不管你怎么出,得的分数都是一样的.
然后这题就滑稽了.

#include<bits/stdc++.h> //Ithea Myse Valgulious
namespace chtholly{//老样子省略快读.
using namespace std;
const int yuzu=1e5;
char c[yuzu|10];
int main(){
scanf("%s",c);
int cnt=0,i,len=strlen(c);
for (i=0;i<len;++i){
  cnt+=c[i]=='p';
  }
write(len/2-cnt);
}

B

给出n,求符合0<=u<=n且0<=v<=n并且存在两个非负整数a,b满足a^b=u(^指按位异或),a+b=v的(u,v)的对数.
数论题.不能暴力枚举,我们先看看u,v,a,b之间满足的关系.

a+b=((a&b)<<1)+(a^b);
不知道大家是否知道这个规律.
则v=((a&b)<<1)+u.
那么v必须要大于或者等于u并且v-u为偶数.
但是很遗憾,虽然题解里说了这个,本题还是不能简单做的.

考虑以下的递推式.
dp[n]=dp[n/2]+dp[(n-1)/2]+dp[(n-2)/2].
然后用map来储存答案,一个记忆化,游戏结束.
这个递推式怎么来的我也不知道了.

#include<bits/stdc++.h> //Ithea Myse Valgulious
namespace chtholly{
using namespace std;
const int mod=1e9+7;
map<ll,ll> dp;
ll n;

ll dfs(ll n){
if (n<2) return n+1;
if (dp[n]) return dp[n];
return dp[n]=n&1?(dfs((n>>1)-1)%mod+2*dfs(n>>1))%mod
                :(dfs((n>>1)-1)*2%mod+dfs(n>>1))%mod;
}

int main(){
read(n);
write(dfs(n));
}

C

给出一个字符串,两人轮流操作,每次去掉其中一个字母(不能去掉两边的字母).
任何时候不能出现两个相邻的字母相同的情况.谁不能去掉一个字母谁就输了.
问先手后手谁必胜.

结论题.谁必胜的影响因素有两个,首尾字符相等和字符串长度的奇偶性.
然后异或判断一下.至于证明我这里没有什么时间,大家会日语的话可以去看题解.

#include<bits/stdc++.h> //Ithea Myse Valgulious
namespace chtholly{
using namespace std;
const int yuzu=1e5;
char c[yuzu|10];

int main(){
scanf("%s",c+1);
int i,n=strlen(c+1);
puts(c[1]!=c[n]^(n&1)?"Second":"First");
}

D

一张无向图由公路和铁路网连接.
求对于每一个点来说,它仅通过公路和仅通过铁路都能走到的点的个数.

一开始想想是搜索,后来发现根本不用.
由于无向图,只要用两个并查集判一下就可以了.
用一个pair存储某个点在公路连成的并查集的祖先和铁路连成的并查集的祖先,用map瞎搞一下.

#include<bits/stdc++.h> //Ithea Myse Valgulious
using namespace std;
const int yuzu=2e5;
typedef pair<int,int> pii;
typedef int fuko[yuzu|10];
fuko ans;
map<pii,int> mp;
int n,k,l;

struct dsu{
fuko fa;
void init(int n){
  for (int i=1;i<=n;++i) fa[i]=i;
  }
int find(int x){
  return fa[x]==x?x:fa[x]=find(fa[x]);
  }
void mg(int u,int v){
  fa[find(u)]=find(v);
  }
}gl,tl;

int main(){
int i;
scanf("%d%d%d",&n,&k,&l);
gl.init(n),tl.init(n);
for (i=1;i<=k;++i){
  int u,v;
  scanf("%d%d",&u,&v);
  gl.mg(u,v);
  }
for (i=1;i<=l;++i){
  int u,v;
  scanf("%d%d",&u,&v);
  tl.mg(u,v);
  }
for (i=1;i<=n;++i){
  mp[pii(gl.find(i),tl.find(i))]++; 
  }
for (i=1;i<=n;++i){
  printf("%d ",mp[pii(gl.find(i),tl.find(i))]);
  }
}

E

直线上按坐标从小到大给出一些点,你从第一个点开始要到达全部的点.
你可以走一个单位长度,花费是A.你也可以(召唤白井黑子)空间移动到任何位置,花费是B.
求最小花费.

我和Styx对视了一眼笑了出来.好像这道题最简单.
首先可以证明折返的花费肯定不会小于不折返的花费,因此只要从第一个点开始逐个遍历即可.
那么对于任何两个相邻点,如果它们之间的距离dis*A < B,我们就走路过去,否则就传送过去.
用以上贪心即可AC.
注意有概率爆int.

#include<bits/stdc++.h> //Ithea Myse Valgulious
namespace chtholly{//这里我留一个快读模板.
typedef long long ll;
#define re0 register int
#define rec register char
#define rel register ll
#define gc getchar
#define pc putchar
#define p32 pc(' ')
#define pl puts("")
/*By Citrus*/
inline int read(){
  int x=0,f=1;char c=gc();
  for (;!isdigit(c);c=gc()) f^=c=='-';
  for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
  return f?x:-x;
  }
inline bool read(ll &x){
  x=0;int f=1;char c=gc();
  for (;!isdigit(c)&&c^-1;c=gc()) f^=c=='-';
  if (!~c) return 0;
  for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
  return x=f?x:-x,1;
  }
template <typename mitsuha>
inline int write(mitsuha x){
  if (!x) return pc(48);
  if (x<0) x=-x,pc('-');
  int bit[20],i,p=0;
  for (;x;x/=10) bit[++p]=x%10;
  for (i=p;i;--i) pc(bit[i]+48);
  }
inline char fuhao(){
  char c=gc();
  for (;isspace(c);c=gc());
  return c;
  }
}using namespace chtholly;
using namespace std;
const int yuzu=1e5;
ll x[yuzu|10];

int main(){
ll i,n=read(),a=read(),b=read();
for (i=1;i<=n;++i) x[i]=read();
ll ans=0;
for (i=2;i<=n;++i){
  int dis=x[i]-x[i-1];
  ans+=min(a*dis,b);
  }
write(ans);
}

猜你喜欢

转载自blog.csdn.net/qq_31908675/article/details/80260327