codeforces:65

前言

C和D题比较不错,ABE都有亿些很恶心的细节问题(尤其是E)
E题自己编写1A的读者,可以到@asta处领取8888元的现金红包(bushi)

CF65A Harry Potter and Three Spells

Description \text{Description} Description

你可以用 a a a 克沙子得到 b b b 克叶子, c c c 克叶子得到 d d d 克金子, e e e 克金子得到 f f f 克沙子.
给出 a , b , c , d , e , f a,b,c,d,e,f a,b,c,d,e,f,求出是否可以通过有限的沙子得到无限的金子.

Solution \text{Solution} Solution

不难得出一个有解的条件: b × d × f > a × b × c b\times d\times f>a\times b\times c b×d×f>a×b×c.
但这是建立在六个变量均正的情况.
考虑有哪些有解的情况没有考虑.

  1. c = 0 , d ≠ 0 c=0,d\neq0 c=0,d=0 :金子可以无中生有,根本不需要叶子
  2. a = 0 , b ≠ 0 , d ≠ 0 a=0,b\ne0,d\ne0 a=0,b=0,d=0 : 叶子可以无中生有,且可以从叶子转化成金子
  3. e = 0 , f ≠ 0 , b ≠ 0 , d ≠ 0 e=0,f\ne0,b\ne0,d\ne0 e=0,f=0,b=0,d=0 : 沙子可以无中生有,但是这个其实不用特判,因为符合原来的式子

特判打全即可,不用开 longlong.

Code \text{Code} Code

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=4e5+100;
const int mod=998244353;
//char buf[1<<23],*p1=buf,*p2=buf,obuf[1<<23],*O=obuf;
//#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
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;

signed main(){
#ifndef ONLINE_JUDGE
  freopen("a.in","r",stdin);
  freopen("a.out","w",stdout);
#endif
  int a=read(),b=read(),c=read(),d=read(),e=read(),f=read();
  if(b*d*f>a*c*e||(d&&c==0)||(d&&b&&a==0)) printf("Ron");
  else printf("Hermione");
}
/*
*/

CF65B Harry Potter and the History of Magic

Description \text{Description} Description

给你 n n n 个年份 x 1... n x_{1...n} x1...n.

请你更改一些数字,使年份按时间顺序(即非递减)排列,以使其中没有任何日期晚于 2011 2011 2011 或早于 1000 1000 1000.

在每个日期中最多只能将一位数字改成别的数字.
1 ≤ n ≤ 10000 , 1000 ≤ x i ≤ 9999 1\le n\le10000,1000\le x_i\le9999 1n10000,1000xi9999.

Solution \text{Solution} Solution

不难发现贪心策略,使前面的年份尽可能的小,一定是不劣的.
分情况讨论,如果大于前一项,从高位开始尝试往低改;如果小于前一项,就从低位开始尝试往高改即可.
最后判一下是否超过 2011 2011 2011.
实现上,有一些上下取整的细节,但整体还不算太恶心.

Code \text{Code} Code

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=4e5+100;
const int mod=998244353;
//char buf[1<<23],*p1=buf,*p2=buf,obuf[1<<23],*O=obuf;
//#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
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[1050],mi[5]={1,10,100,1000,10000};
inline int f(int x,int pos){
  return x%mi[pos+1]/mi[pos];
}
signed main(){
#ifndef ONLINE_JUDGE
  freopen("a.in","r",stdin);
  freopen("a.out","w",stdout);
#endif
  n=read();
  for(int i=1;i<=n;i++) a[i]=read();
  a[0]=1000;
  for(int i=1;i<=n;i++){
    if(a[i]>=a[i-1]){
      int d=a[i]-a[i-1];
      for(int k=3;k>=0;k--){
	int o=f(a[i],k);
	if(!o||d<mi[k]) continue;
	a[i]-=min(d/mi[k]*mi[k],o*mi[k]);break;
      }
    }
    else{
      int d=a[i-1]-a[i];
      for(int k=0;k<=3;k++){
	int o=9-f(a[i],k);
	if(o*mi[k]<d) continue;
	a[i]+=(d+mi[k]-1)/mi[k]*mi[k];
	//printf("k=%d o=%d d=%d add=%d\n",k,o,d,(d+mi[k]-1)/mi[k]);
	break;
      }
    }
    //printf("%d\n",a[i]);
    if(a[i]<a[i-1]){
      printf("No solution");return 0;
    }
  }
  if(a[n]>2011) printf("No solution");
  else{
    for(int i=1;i<=n;i++) printf("%d\n",a[i]);
  }
}
/*
*/

CF65C Harry Potter and the Golden Snitch

Description \text{Description} Description

有一个金色飞贼沿着 ( x 1 , y 1 , z 1 ) → ( x 2 , y 2 , z 2 ) → . . . → ( x n , y n , z n ) (x_1,y_1,z_1)\to (x_2,y_2,z_2)\to ...\to (x_n,y_n,z_n) (x1,y1,z1)(x2,y2,z2)...(xn,yn,zn) 的轨迹以 v s v_s vs 的速度匀速运动.
哈利的最大速度是 v p v_p vp,初始位置是 ( p x , p y , p z ) (p_x,p_y,p_z) (px,py,pz).
请求出哈利抓住金色飞贼的最快时间和抓住它的位置.
n ≤ 10000 , v p ≥ v s n\le 10000,v_p\ge v_s n10000,vpvs.

Solution \text{Solution} Solution

v p ≥ v s v_p\ge v_s vpvs 是本题的关键条件,这意味着本题的答案是具有单调性的.
所以二分时间判断是否可以抓到即可.

注意:

  1. 虽然精度只要求到 1 0 − 6 10^{-6} 106,但是由于坐标的计算会放大精度,所以我们的精度需要开到 1 0 − 12 10^{-12} 1012(这里不是平方关系,只是要开小一点).
  2. 需要开 long double,否则精度太小可能会死循环.
  3. 注意不等号的精度问题.

Code \text{Code} Code

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define double long double 
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=1e4+100;
const double eps=1e-12;
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;
double t[N],sum[N],v;
double x[N],y[N],z[N];
double X,Y,Z,V;
inline double tim(double x,double y,double z){
  return sqrt((x-X)*(x-X)+(y-Y)*(y-Y)+(z-Z)*(z-Z))/V;
}
bool check(double w){
  for(int i=1;i<=n;i++){
    if(sum[i]>=w-eps){
      double o=(w-sum[i-1])/t[i];
      double xx=x[i-1]+(x[i]-x[i-1])*o,yy=y[i-1]+(y[i]-y[i-1])*o,zz=z[i-1]+(z[i]-z[i-1])*o;
      return tim(xx,yy,zz)-eps<w;
    }
  }
  return false;
}
signed main(){
#ifndef ONLINE_JUDGE
  freopen("a.in","r",stdin);
  freopen("a.out","w",stdout);
#endif
  n=read();
  for(int i=0;i<=n;i++) scanf("%Lf%Lf%Lf",&x[i],&y[i],&z[i]);
  scanf("%Lf%Lf%Lf%Lf%Lf",&V,&v,&X,&Y,&Z);
  for(int i=1;i<=n;i++){
    double d=sqrt((x[i]-x[i-1])*(x[i]-x[i-1])+
		  (y[i]-y[i-1])*(y[i]-y[i-1])+(z[i]-z[i-1])*(z[i]-z[i-1]));
    t[i]=d/v;sum[i]=sum[i-1]+t[i];
  }
  if(tim(x[n],y[n],z[n])>sum[n]+eps){
    printf("NO\n");return 0;
  }
  double st=0,ed=sum[n];
  while(ed-st>eps){
    double mid=(st+ed)/2;
    if(check(mid)) ed=mid;
    else st=mid;
  }
  printf("YES\n%.10Lf\n",st);
  double w=st;
  for(int i=1;i<=n;i++){
    if(sum[i]>w-eps){
      double o=(w-sum[i-1])/t[i];
      double xx=x[i-1]+(x[i]-x[i-1])*o,yy=y[i-1]+(y[i]-y[i-1])*o,zz=z[i-1]+(z[i]-z[i-1])*o;
      printf("%.10Lf %.10Lf %.10Lf",xx+eps,yy+eps,zz+eps);return 0;
    }
  }
}
/*
*/

CF65D Harry Potter and the Sorting Hat

Description \text{Description} Description

4 4 4 个变量 G , R , S , H G,R,S,H G,R,S,H,初始的值均为 0 0 0.
给出一个长度为 n n n 的字符串,从前往后进行以下过程:

  1. 若为 G , R , S , H G,R,S,H G,R,S,H 四者之一,则给对应的变量加一.
  2. 否则(为 ? ? ? ),就给四个变量中最小的加一,若有多个最小值,则给任意一个加一.

求处理完整个字符串后,四个变量是否有可能成为(非严格)最小值.
n ≤ 10000 n\le 10000 n10000

Solution \text{Solution} Solution

设计状态为 ( i , a , b , c , d ) (i,a,b,c,d) (i,a,b,c,d) 表示进行到第 i i i 个字符,四个变量分别为 a , b , c , d a,b,c,d a,b,c,d.
注意到,由于每次都只有在对相同的最小值加一时才会导致状态的分裂,并且可能会再后面的问号时合并状态,所以对于同一个 i i i,状态数是收敛的.
直接 dfs 暴搜加 hash 去重即可.

Code \text{Code} Code

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define double long double 
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=1e4+100;
const double eps=1e-12;
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 x[N];
map<ll,bool>mp;
bool vis[5];
void dfs(int k,int a,int b,int c,int d){
  int mn=min(a,min(b,min(c,d)));
  if(k>n){
    if(a==mn) vis[1]=1;
    if(b==mn) vis[2]=1;
    if(c==mn) vis[3]=1;
    if(d==mn) vis[4]=1;
    return;
  }
  ll o=1ll*a*(n+1)*(n+1)*(n+1)+1ll*b*(n+1)*(n+1)+1ll*c*(n+1)+d;
  if(mp[o]) return;
  if(x[k]){
    if(x[k]==1) dfs(k+1,a+1,b,c,d);
    else if(x[k]==2) dfs(k+1,a,b+1,c,d);
    else if(x[k]==3) dfs(k+1,a,b,c+1,d);
    else if(x[k]==4) dfs(k+1,a,b,c,d+1);   
  }
  else{
    if(a==mn) dfs(k+1,a+1,b,c,d);
    if(b==mn) dfs(k+1,a,b+1,c,d);
    if(c==mn) dfs(k+1,a,b,c+1,d);
    if(d==mn) dfs(k+1,a,b,c,d+1);
  }
  mp[o]=1;
}
signed main(){
#ifndef ONLINE_JUDGE
  freopen("a.in","r",stdin);
  freopen("a.out","w",stdout);
#endif
  n=read();
  char c;
  for(int i=1;i<=n;i++){
    scanf(" %c",&c);
    if(c=='G') x[i]=1;
    else if(c=='H') x[i]=2;
    else if(c=='R') x[i]=3;
    else if(c=='S') x[i]=4;
  }
  dfs(1,0,0,0,0);
  if(vis[1]) printf("Gryffindor\n");
  if(vis[2]) printf("Hufflepuff\n");
  if(vis[3]) printf("Ravenclaw\n");
  if(vis[4]) printf("Slytherin\n");
}
/*
*/

CF65E Harry Potter and Moving Staircases

Description \text{Description} Description

有一个 n n n 个点 m m m 条边的无向图,哈利初始在结点 1 1 1,哈利可以沿着边任意移动,过程中任意时刻可以选择一条边,改变它的一个端点,但是每条边只能被修改一次.
请构造一种方案使哈利走遍所有楼层,或者报告无解.
n ≤ 1 0 5 , m ≤ 2 × 1 0 5 n\le 10^5,m\le 2\times10^5 n105,m2×105

Solution \text{Solution} Solution

阴间大特判题.
容易找到一种比较正确的整体方案:dfs,过程中——

  1. 若出边连向走过的结点,则直接把边改向一个未走过的结点,递归 dfs.
  2. 若出边连向未走过的结点,则先递归 dfs,回溯时在把边改向一个未走过的结点,递归 dfs.

不难发现这样一定是最优的.
然后就是 通过观察 WA 的数据 处理亿点点细节问题:

  1. 改边连向的点应该优先连向有度数的点.
  2. 有可能会出现 1 1 1 没有度数但存在解的情况,这时候需要尝试把一条边直接改为连向 1 1 1,同时这个边不应该是一条边连接两个点的简单图形.(否则改完还是会死掉)
  3. 改为连向 1 1 1 的边应该优先选择成环的边,这样会更优.

具体实现留给读者自行思考.(或者参考我实现丑的一批的代码)

Code \text{Code} Code

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define double long double 
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=4e5+100;
const double eps=1e-12;
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;
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 jd[N],du[N];
set<int>s1,s2;
int dfn[N<<2],tim,tot;
struct edge{
  int x,y,id;
}e[N];
int siz[N];
int ans[N],num;
int flag,O,ID;
void print(){
  int pl(1);
  if(!O) flag=0;
  printf("YES\n%d\n",tot+flag);
  for(int i=1;i<=tim+1;i++){
    if(dfn[i]) ans[++num]=dfn[i];
    else{
      printf("%d ",num);
      for(int j=1;j<=num;j++) printf("%d ",ans[j]);
      putchar('\n');   
      num=0;
      if(pl<=tot){
	printf("%d %d %d\n",e[pl].id,e[pl].x,e[pl].y);   
	++pl;
      }
    }
    if(i==1&&flag){
      printf("1 1\n%d %d 1\n",ID,O);num=0;
    }
  }
  return;
}
int fa[N];
vector<int> v[N];
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
bool vis[N];
void dfs(int x){
  dfn[++tim]=x;vis[x]=1;
  for(int i=fi[x];~i;i=p[i].nxt){
    if(jd[i]==1) continue;
    int f=jd[i];
    jd[i]=jd[i^1]=1;
    int to=p[i].to;
    //printf("x=%d to=%d\n",x,to);
    dfs(to);
    dfn[++tim]=x;
    if((!s1.empty()||!s2.empty())&&!f){
      int o;
      if(!s1.empty()) o=(*s1.begin()),s1.erase(o);
      else o=(*s2.begin()),s2.erase(o);
      //printf("x=%d o=%d\n",x,o);
      dfn[++tim]=0;e[++tot]=(edge){x,o,i/2+1};
      dfs(o);
      dfn[++tim]=x;
    }
  }
  return;
}
int E;
signed 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();
  for(int i=1;i<=n;i++) fa[i]=i;
  for(int i=1;i<=m;i++){
    e[i].x=read();e[i].y=read();
    ++du[e[i].x];++du[e[i].y];
    if(find(e[i].x)==find(e[i].y)){
      E=i;
    }
    else fa[find(e[i].x)]=find(e[i].y);
  }
  if(du[1]==0){
    flag=1;
    if(E){
      e[E].y=1;O=e[E].x;ID=E;
    }
    else{
      for(int i=1;i<=m;i++){
	if(du[e[i].x]<=1) swap(e[i].x,e[i].y);
	if(du[e[i].x]>1){
	  e[i].id=1;O=e[i].x;ID=i;
	  e[i].y=1;break;
	}
      }
    }
  }
  memset(du,0,sizeof(du));
  for(int i=1;i<=n;i++) fa[i]=i;
  for(int i=1;i<=m;i++){
    int x=e[i].x,y=e[i].y;
    addline(x,y);addline(y,x);
    fa[find(x)]=find(y);
    ++du[x];++du[y];
    if(e[i].id) jd[cnt]=jd[cnt^1]=2;
  }
  //for(int i=1;i<=n;i++) debug("i=%d fa=%d\n",i,fa[i]);
  for(int i=2;i<=n;i++){
    if(i==find(i)&&find(1)!=i){
      if(du[i]) s1.insert(i);
      else s2.insert(i);
    }
  }
  dfs(1);
  if(!s1.empty()||!s2.empty()) printf("NO\n");
  else print();
  return 0;
}
/*

*/

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值