codeforces:812(div2):总结

前言

比较水的一场比赛
E题几乎是一本通原题而我还是不会做qwq

A - Sagheer and Crossroads

有一个十字路口,给出四个路口的车是否可以左转/右转/直行,并且给出每个路口的行人是否可以通过,求是否出现车和人冲突的情况

阅读理解题(其实只是我英语太差了),读懂题意直接模拟即可

#include
using namespace std;
#define ll long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=5e5+100;
const int mod=1e9+7;
const double eps=1e-9;
inline ll read(){
  ll x(0),f(1);char c=getchar();
  while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
  while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
  return x*f;
}

int n,m;

int a[5][5],d[4]={0,3,2,1};
bool vis[5];
int main(){
#ifndef ONLINE_JUDGE
  freopen("a.in","r",stdin);
  freopen("a.out","w",stdout);
#endif
  for(int i=1;i<=4;i++){
    for(int j=1;j<=4;j++) a[i][j]=read();
  }
  for(int i=1;i<=4;i++){
    for(int j=1;j<=3;j++){
      if(a[i][j]){
	//printf("i=%d j=%d to=%d\n",i,j,(i+d[j]-1)%4+1);
	vis[(i+d[j]-1)%4+1]=1,vis[i]=1;
      }
    }
  }
  for(int i=1;i<=4;i++){
    if(vis[i]&&a[i][4]){
      printf("YES");return 0;
    }
  }
  printf("NO\n");
  return 0;
}

B - Sagheer, the Hausmeister

给出一个n层的房屋,每层有m个房间,最左边和最右边有两个楼梯
有一些房间的灯是开着的,求一条从第一层左楼梯开始的最短的不下楼的路径,关掉所有的灯
n ≤ 15 , m ≤ 100 n \leq 15,m \leq 100 n15,m100

dp入门水题,设计 d p i , 0 / 1 dp_{i,0/1} dpi,0/1 表示从在第 i 层的左/右楼梯(本层的灯还没有关)的最短路径,枚举关灯方式进行转移即可
时间复杂度 O ( n × m ) O(n \times m) O(n×m)瓶颈竟然在于输入
但是这题还WA了两次…有一些特殊情况需要特判:

  1. 如果当前楼的上面一盏灯都没有就不必继续上楼了
  2. 存在整栋楼没有灯的情况
#include
using namespace std;
#define ll long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=5e5+100;
const int mod=1e9+7;
const double eps=1e-9;
inline ll read(){
  ll x(0),f(1);char c=getchar();
  while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
  while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
  return x*f;
}

int n,m;
int dp[18][2];
int l[18],r[18];
int main(){
#ifndef ONLINE_JUDGE
  freopen("a.in","r",stdin);
  freopen("a.out","w",stdout);
#endif
  int top(0);
  n=read();m=read()+2;
  for(int i=n;i>=1;i--){
    for(int j=1;j<=m;j++){
      int x(0);scanf("%1d",&x);
      if(x){
	if(!top) top=i;
	if(!l[i]) l[i]=j;
	r[i]=j;
      }
    }
  }
  memset(dp,0x3f,sizeof(dp));
  dp[1][0]=0;
  n=top;
  if(!top){
    printf("0");return 0;
  }
  for(int i=1;i<n;i++){
    if(!l[i]){
      dp[i+1][0]=dp[i][0]+1;
      dp[i+1][1]=dp[i][1]+1;
    }
    else{
      dp[i+1][0]=min(dp[i][0]+2*(r[i]-1)+1,dp[i][1]+m);
      dp[i+1][1]=min(dp[i][1]+2*(m-l[i])+1,dp[i][0]+m);
      //printf("i=%d dp0=%d dp1=%d\n",i+1,dp[i+1][0],dp[i+1][1]);
    }
  }
  int ans=min(dp[n][0]+r[n]-1,dp[n][1]+m-l[n]);
  printf("%d\n",ans);
  return 0;
}

C - Sagheer and Nubian Market

给出 n n n 个元素的基本价格 a i a_i ai ,如果你选择了k个元素 a x 1 , a x 2 , . . . , a x k a_{x_1},a_{x_2},...,a_{x_k} ax1,ax2,...,axk,那么每个元素的真实价格就是 a x i + k ∗ x i a_{x_i}+k*x_i axi+kxi(换句话说就是加上总数量乘下角标)
现在有 s s s 元钱,求最多能买到几个元素

二分答案,二分后每个元素的真实价格就确定了,sort后取前 k k k 个看有没有超过 s s s 即可

#include
using namespace std;
#define ll long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=2e5+100;
const int mod=1e9+7;
const double eps=1e-9;
inline ll read(){
  ll x(0),f(1);char c=getchar();
  while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
  while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
  return x*f;
}

int n,m,s;
ll a[N],b[N];
ll calc(int k){
  for(int i=1;i<=n;i++) b[i]=a[i]+1ll*i*k;
  sort(b+1,b+1+n);
  ll res(0);
  for(int i=1;i<=k;i++) res+=b[i];
  return res;
}
int main(){
#ifndef ONLINE_JUDGE
  freopen("a.in","r",stdin);
  freopen("a.out","w",stdout);
#endif
  n=read();s=read();
  for(int i=1;i<=n;i++) a[i]=read();
  int st=0,ed=n;
  while(st<ed){
    int mid=(st+ed+1)>>1;
    if(calc(mid)<=s) st=mid;
    else ed=mid-1;
  }
  printf("%d %lld\n",st,calc(st));
  return 0;
}

D - Sagheer and Kindergarten

如果想自己做一下这道题,建议直接去原题面

n n n 个孩子和 m m m 个玩具,孩子会提出一共k个对玩具的要求,满足如下性质:

  1. 如果一个孩子要求的玩具是闲置的(也就是不在任何一个孩子手中),他就会得到那个玩具,否则他就会一直等待
  2. 每个孩子可能会要求得到若干个玩具,只有当其得到 所有玩具 时,才会满意,并在玩一会玩具后返还所有的玩具,而在此之前会一直霸占着所有已有的玩具
  3. 如果变得空闲的玩具被两个孩子要求,会优先满足靠前的要求
  4. 如果一个孩子的某个要求没有被满足,他就不会再要求别的玩具
  5. 如果一个孩子发现自己永远也得不到满足,就会开始哭
  6. 保证在当前的k个要求中,没有孩子在哭

有q个独立的询问,每次增加一条要求(不一定满足第4条和第6条),求有多少个孩子在哭

真正的阅读理解题(上面这一大陀已经是我部分精简抽象后的结果),难点似乎就在于转化题意,后面就比较显然了

可以把对玩具的要求转化为孩子之间的依赖关系
具体的,如果x要求玩具w,上一个要求玩具w的人是y,就连一条有向边 y − > x y->x y>x,表示只有y满足之后x才能满足
一个孩子哭泣,当且仅当他在某个环中
由于性质4和性质6,连成的图一定是一个森林
每次判断给出的新的依赖关系是否是返祖边,如果是,这条链就会形成一个环,否则必然不会成环
判断返祖不必lca,可以直接用dfs序判定子树的方法,单次询问 O ( 1 ) O(1) O(1)

#include
using namespace std;
#define ll long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=2e5+100;
const int mod=1e9+7;
const double eps=1e-9;
inline ll read(){
  ll x(0),f(1);char c=getchar();
  while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
  while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
  return x*f;
}

int n,m,k,q;
int bel[N];
struct node{
  int to,nxt;
}p[N<<1];
int fi[N],cnt;
inline void addline(int x,int y){
  p[++cnt]=(node){y,fi[x]};fi[x]=cnt;
  return;
}

int du[N];
int siz[N],pos[N],tim,dep[N];
void dfs(int x,int f){
  pos[x]=++tim;dep[x]=dep[f]+1;
  siz[x]=1;
  for(int i=fi[x];~i;i=p[i].nxt){
    int to=p[i].to;
    dfs(to,x);
    siz[x]+=siz[to];
  }
  return;
}
int main(){
#ifndef ONLINE_JUDGE
  freopen("a.in","r",stdin);
  freopen("a.out","w",stdout);
#endif
  memset(fi,-1,sizeof(fi));cnt=-1;
  n=read();m=read();k=read();q=read();
  for(int i=1;i<=k;i++){
    int x=read(),y=read();
    if(bel[y]) addline(bel[y],x),du[x]++;
    bel[y]=x;    
  }
  for(int i=1;i<=n;i++){
    if(!du[i]) dfs(i,0);
  }
  for(int i=1;i<=q;i++){
    int x=read(),y=read();
    int o=bel[y];
    if(pos[x]<=pos[o]&&pos[o]<=pos[x]+siz[x]-1) printf("%d\n",siz[x]);
    else printf("0\n");
  }
  return 0;
}

E - Sagheer and Apple Tree

给定一个树,第i个节点上有 a i a_i ai个苹果
两人轮流行动,每次可以选择一个有苹果的节点,进行下列行为之一:

  1. 如果是叶子节点,就吃掉节点上的一些苹果
  2. 如果不是叶子,就把节点上的一些苹果移到他的一个儿子上

保证从根到所有叶子的距离的奇偶性相同
现在,后手方可以交换任意两个节点 ( u , v ) (u,v) (u,v)上的苹果数,求能使双方最优情况下后手获胜的无序点对 ( u , v ) (u,v) (u,v)的数量

ybt有一道情景几乎一模一样的题
然而还是并不会
qwq
感觉这个题的题解讲的更加透彻
把叶子和到叶子距离为偶数的点染成黑色,距离为偶数的点染成白色
那么,每次操作其实就是使黑色节点的某一堆的石子增加或减少
那么和nim游戏的唯一区别就是这里还可以增加石子
但是其实并不影响,因为必败方尝试增加石子后,必胜方都可以把增加的石子减少回去
所以后手胜的充要条件和nim一样,就是黑点权值异或和为0
然后合法点对就可以分类讨论一下然后开个map随便做了

#include
using namespace std;
#define ll long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=2e5+100;
const int mod=1e9+7;
const double eps=1e-9;
inline ll read(){
  ll x(0),f(1);char c=getchar();
  while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
  while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
  return x*f;
}

int n;
struct node{
  int to,nxt;
}p[N<<1];
int fi[N],cnt;
inline void addline(int x,int y){
  p[++cnt]=(node){y,fi[x]};fi[x]=cnt;
  return;
}

int num[2];
int a[N],op[N],s;
map<int,int>mp;
void dfs(int x){
  if(fi[x]==-1){
    op[x]=1;return;
  }
  for(int i=fi[x];~i;i=p[i].nxt){
    int to=p[i].to;
    dfs(to);
    op[x]=op[to]^1;
  }  
  return;
}

int main(){
#ifndef ONLINE_JUDGE
  freopen("a.in","r",stdin);
  freopen("a.out","w",stdout);
#endif
  memset(fi,-1,sizeof(fi));cnt=-1;
  n=read();
  for(int i=1;i<=n;i++) a[i]=read();
  for(int i=2;i<=n;i++) addline((int)read(),i);
  dfs(1);
  for(int i=1;i<=n;i++){
    ++num[op[i]];
    if(op[i]) s^=a[i];
  }
  if(s==0){
    ll ans=1ll*num[0]*(num[0]-1)/2+1ll*num[1]*(num[1]-1)/2;
    for(int i=1;i<=n;i++){
      if(op[i]) mp[a[i]]++;
    }
    for(int i=1;i<=n;i++){
      if(!op[i]) ans+=mp[a[i]];
    }
    printf("%lld\n",ans);
  }
  else{
    ll ans(0);
    for(int i=1;i<=n;i++){
      if(op[i]) mp[a[i]^s]++;
    }
    for(int i=1;i<=n;i++){
      if(!op[i]) ans+=mp[a[i]];
    }
    printf("%lld\n",ans);
  }
  return 0;
}

你可能感兴趣的:(杂记,codeforces)