Codeforces Round #517(Div. 1) 题解

A.Cram Time

显然$a,b$都是被用完的,我们也只会用一个前缀。

#include <bits/stdc++.h>
#define for1(a,b,i) for(int i=a;i<=b;++i)
#define FOR2(a,b,i) for(int i=a;i>=b;--i)
using namespace std;
typedef long long ll;
inline int read() {
    int f=1,sum=0;
    char x=getchar();
    for(;(x<'0'||x>'9');x=getchar()) if(x=='-') f=-1;
    for(;x>='0'&&x<='9';x=getchar()) sum=sum*10+x-'0';
    return f*sum;
}

#define M 100005
int n,m;

vector <int> p,q;

inline bool check(int x) {return 1ll*x*(1+x)/2<=n+m;}

int main () {
    //freopen("a.in","r",stdin);
    n=read(),m=read();
    int l=1,r=1e5,mid,ans=0;
    while (l<=r) {
        mid=l+r>>1;
        if(check(mid)) ans=mid,l=mid+1;
        else r=mid-1;
    }
    
    FOR2(ans,1,i) 
        if(n>=i) n-=i,q.push_back(i);
        else m-=i,p.push_back(i);
    int size=q.size();
    printf("%d
",size);
    for1(1,size,i) printf("%d ",q[i-1]);
    puts("");
    size=p.size();
    printf("%d
",size);
    for1(1,size,i) printf("%d ",p[i-1]);
    puts("");
}
View Code

B.Minimum path

我们一定是把某条路径的前几个不是$a$的变成$a$。

dp出来最长的$a$的前缀长度,然后把所有满足条件的点都保存下来。

之后逐位贪心,因为$dis$不断增大,所以是$O(n^2)$的。

#include <bits/stdc++.h>
#define for1(a,b,i) for(int i=a;i<=b;++i)
#define FOR2(a,b,i) for(int i=a;i>=b;--i)
using namespace std;
typedef long long ll;
inline int read() {
    int f=1,sum=0;
    char x=getchar();
    for(;(x<'0'||x>'9');x=getchar()) if(x=='-') f=-1;
    for(;x>='0'&&x<='9';x=getchar()) sum=sum*10+x-'0';
    return f*sum;
}

#define M 2005
int n,m;
char a[M][M];
int f[M][M],size;
bool vis[M][M];
struct node {int x,y;}q[M*M],p[M*M];

inline bool check(int c) {
    c+='a'-1;
    for1(1,size,i) {
        int x=q[i].x;
        int y=q[i].y;
        if(a[x+1][y]==c||a[x][y+1]==c) return 1;
    }
    return 0;
}

inline void move_(int c) {
    c+='a'-1;
    int cnt=0;
    for1(1,size,i) {
        int x=q[i].x;
        int y=q[i].y;
        if(a[x+1][y]==c&&!vis[x+1][y]) vis[x+1][y]=1,p[++cnt]=(node){x+1,y};
        if(a[x][y+1]==c&&!vis[x][y+1]) vis[x][y+1]=1,p[++cnt]=(node){x,y+1};
    }
    size=cnt;
    for1(1,size,i) q[i]=p[i];
}

int main () {
    //freopen("a.in","r",stdin);
    n=read(),m=read();
    for1(1,n,i) scanf("%s",a[i]+1);
    if(m>=2*n-1) {
        for1(1,2*n-1,i) putchar('a');
        puts("");
        return 0;
    }
    
    memset(f,0x3f,sizeof(f));
    f[1][1]=a[1][1]!='a';
    for1(1,n,i) for1(1,n,j) {
        int c=a[i][j]!='a';
        if(i-1) f[i][j]=min(f[i][j],f[i-1][j]+c);
        if(j-1) f[i][j]=min(f[i][j],f[i][j-1]+c);
    }
    
    int da=0;
    for1(1,n,i) for1(1,n,j) if(f[i][j]<=m) da=max(da,i+j-1);
    for1(1,n,i) for1(1,n,j) if(i+j-1==da&&f[i][j]<=m) q[++size]=(node){i,j};
    for1(1,da,i) putchar('a');
    if(f[1][1]>m) q[++size]=(node){1,1},da=1,putchar(a[1][1]);
    for1(da+1,2*n-1,i) {
        int x=1;
        while (!check(x)) ++x;
        move_(x);
        putchar('a'+x-1);
    }
    puts("");
}
View Code

C.Triple Flips

我觉得我学习了一种很好的思路。

当看到题解的一刻我觉得这个题很不好。

但是当我仔细分析之后我觉得这是一种非常正确且有效的思路。

首先我们对于$n$很小的点可以暴力状压,发现$nleq 7$才可能无解。

接下来我们就考虑题目中给出的上界$left lfloor frac{n}{3} ight floor+12$。

我们可以理解为每一步操作至少使得端点为$1$的序列长度减$3$,之后当长度变小时就可以用状压了。

然后就很简单了。

#include <bits/stdc++.h>
#define for1(a,b,i) for(int i=a;i<=b;++i)
#define FOR2(a,b,i) for(int i=a;i>=b;--i)
using namespace std;
typedef long long ll;
inline int read() {
    int f=1,sum=0;
    char x=getchar();
    for(;(x<'0'||x>'9');x=getchar()) if(x=='-') f=-1;
    for(;x>='0'&&x<='9';x=getchar()) sum=sum*10+x-'0';
    return f*sum;
}

#define M 200005
int n;
bool vis[M];
int a[M],tot,e_size,head[M],dis[M];

set <pair<int,int> > q;
struct node {int v,nxt;}e[M*2];
struct point {int x,y,z;}cc[M];

inline void e_add(int u,int v) {
    e[++e_size]=(node){v,head[u]};
    head[u]=e_size;
}

inline void add_(int x,int y) {
    a[x]^=1,a[y]^=1,a[2*y-x]^=1;
    cc[++tot]=(point){x,y,2*y-x};
}

inline void solve() {
    int m=min(n,12);
    int all=(1<<m)-1;
    for1(0,all,i) {
        for1(1,m,j) {
            for1(j+1,m,k) if(2*k-j<=m) e_add(i,i^(1<<j-1)^(1<<k-1)^(1<<2*k-j-1));
        }
    }
    memset(dis,0x3f,sizeof(dis));
    dis[0]=0;
    q.insert(make_pair(0,0)); 
    while (!q.empty()) {
        auto t=*q.begin();
        q.erase(q.begin());
        if(vis[t.second]) continue;
        vis[t.second]=1;
        for(int i=head[t.second];i;i=e[i].nxt) {
            int v=e[i].v;
            if(dis[v]>dis[t.second]+1) {
                dis[v]=dis[t.second]+1;
                q.insert(make_pair(dis[v],v));
            }
        }
     }
}

inline void trans_(int pre,int Max,int x) {
    if(!x) return;
    for(int i=head[x];i;i=e[i].nxt) {
        int v=e[i].v;
        if(dis[x]==dis[v]+1) {
            int cnt=0;
            int buc[3]={0};
            FOR2(Max,1,j) if((x^v)>>j-1&1) buc[cnt++]=Max-j+1+pre;
            add_(buc[0],buc[1]);
            trans_(pre,Max,v);
            return;
        }
    }
}

int main () {
//    freopen("a.in","r",stdin);
    n=read();
    for1(1,n,i) a[i]=read();
    solve();
    if(n<=12) {
        int zt=0;
        for1(1,n,i) zt=zt*2+a[i];
        if(dis[zt]>n) puts("NO");
        else {
            puts("YES");
            trans_(0,n,zt);
            printf("%d
",tot);
            for1(1,tot,i) printf("%d %d %d
",cc[i].x,cc[i].y,cc[i].z);
        }
        return 0;
    }
    puts("YES");
    for(int i=1;i<=n-12;) {
        while (!a[i]&&i!=n) ++i;
        if(i>n-12) break;
        if(!a[i+1]) {
            if(a[i+2]) add_(i,i+2);
            else add_(i,i+3);
        }
        else {
            if(a[i+2]) add_(i,i+1);
            else {
                int cnt=0;
                int buc[3]={0};
                for1(i+3,i+5,j) if(a[j]) buc[cnt++]=j;
                if(!cnt) {
                    add_(i,i+6),add_(i+1,i+7);
                }
                else if(cnt==1) {
                    add_(i,buc[0]),add_(i+1,i+6);
                }
                else if(cnt==2) {
                    add_(i,buc[0]),add_(i+1,buc[1]);
                }
                else {
                    add_(i+1,i+3),add_(i,i+4);
                }
            }
        }
    }
    
    int zt=0;
    for1(1,12,i) a[i]=a[n-12+i];
    for1(1,12,i) zt=zt*2+a[i];
    
    trans_(n-12,12,zt);
    printf("%d
",tot);
    for1(1,tot,i) printf("%d %d %d
",cc[i].x,cc[i].y,cc[i].z);
}
View Code

D.Familiar Operations

令$x=prod pi^{ai}$。

我们可以$dfs$出所有把$ai$排序之后的序列,即本质不同的序列。

你会发现操作数并不会很多,所以并不用$dfs$出太多。

我之后直接用了$floyd$来搞$dis$,然后枚举到多少个因子就行了。

感觉自己好蠢,我总是想不到边权相同时直接$Bfs$是线性的。

#include <bits/stdc++.h>
#include <unordered_map>
#define for1(a,b,i) for(int i=a;i<=b;++i)
#define FOR2(a,b,i) for(int i=a;i>=b;--i)
using namespace std;
typedef long long ll;
typedef unsigned long long unll;
inline int read() {
    int f=1,sum=0;
    char x=getchar();
    for(;(x<'0'||x>'9');x=getchar()) if(x=='-') f=-1;
    for(;x>='0'&&x<='9';x=getchar()) sum=sum*10+x-'0';
    return f*sum;
}

#define M 3005
#define mod 76543
#define N 1000005
bool vis[N];
int sta[M],zt[N];
int A[M],dis[M][M];
int cnt,a[M][10],f[M],s[N],g[N][10];
int x_[10]={0,2,3,5,7,11,13,17,19};

unordered_map <unll,int> st;

inline void max(int &x,int y) {if(x<y) x=y;}
inline void min(int &x,int y) {if(x>y) x=y;}

inline void dfs(int x,int d,ll sum) {
    if(x==9) {
        f[++cnt]=d;
        for1(0,8,i) a[cnt][i]=sta[i];
        unll t=0;
        for1(1,8,i) if(sta[i]) t=t*mod+sta[i];
        st[t]=cnt;
        return;
    }
    
    for1(0,sta[x-1],i) {
        sta[x]=i;
        dfs(x+1,d*(i+1),sum);
        sum*=x_[x];
        if(sum>200000000) break;
    }
}

inline int get_(int x) {
    int now=x;
    int b[10]={0};
    for1(1,s[x],i) {
        int y=g[x][i];
        while (!(now%y)) now/=y,++b[i];
    }
    sort(b+1,b+s[x]+1);
    
    unll t=0;
    FOR2(s[x],1,i) t=t*mod+b[i];
    return st[t];
}

int main () {
//    freopen("a.in","r",stdin);
    sta[0]=30;
    dfs(1,1,1);
    
    memset(dis,0x3f,sizeof(dis));
    for1(1,cnt,i) dis[i][i]=0;
    for1(1,cnt,i) {
        for1(1,8,j) {
            if(a[i][j]+1>a[i][j-1]) continue;
            unll x=0;
            ++a[i][j];
            for1(1,8,k) if(a[i][k]) x=x*mod+a[i][k];
            --a[i][j];
            if(st.count(x)) {
                int t=st[x];
                dis[i][t]=dis[t][i]=1;
            }
        }
    }
    
    for1(1,cnt,i) 
        for1(1,cnt,j) if(dis[j][i]<100) 
            for1(1,cnt,k) if(dis[i][k]<100) 
                min(dis[j][k],dis[j][i]+dis[i][k]);
    
    for1(1,cnt,i) {
        for1(1,cnt,j) A[j]=dis[i][j],dis[i][j]=1e9;
        for1(1,cnt,j) min(dis[i][f[j]],A[j]);
    }
    
    for1(2,N-5,i) {
        if(s[i]) continue;
        int x=i;
        while (x+4<N) g[x][++s[x]]=i,x+=i;
    }
    
    
    int size=0;
    for1(1,cnt,i) if(!vis[f[i]]) vis[f[i]]=1,zt[++size]=f[i];
    
    int Test_=read();
    while (Test_--) {
        int x=read(),y=read();
        x=get_(x),y=get_(y);
        int ans=1e9;
        for1(1,size,i) min(ans,dis[x][zt[i]]+dis[y][zt[i]]);
        printf("%d
",ans);
    }
}
View Code

E.Rain Protection

思路感觉还是很简单了,就是自己太蠢了,一开始思路错了结果打了好几个版本那个思路。

我们只保存可到达的$(x,0)$的区间。

令$x$为到$i$时的位置,$y$为$i-1$的某个位置,$g(x,i)=x+frac{h*(p[i].x-x)}{p[i].y}$即对面线上的横坐标。

那么我们需要满足的条件是:

egin{cases}
& ext  lleq y leq r \
& ext  y-v*tleq x leq y+v*t \
& ext  g(y,i)-v*tleq g(x,i-1)leq g(y,i)+v*t
end{cases}

并且式子可以化成$k1*y+b1leq x leq k2*y+b2$的形式。

这样解出来就是之后$x$的范围了。

观察式子其实就是以$y$为横坐标会出来一个平行四边形(或者两条平行线)。

直接找到满足横坐标范围内的纵坐标的$min,max$就行了。

好迷啊,必须要加$eps$才能过。

#include <bits/stdc++.h>
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define for1(a,b,i) for(int i=a;i<=b;++i)
#define FOR2(a,b,i) for(int i=a;i>=b;--i)
using namespace std;
typedef long long ll;
inline int read() {
    int f=1,sum=0;
    char x=getchar();
    for(;(x<'0'||x>'9');x=getchar()) if(x=='-') f=-1;
    for(;x>='0'&&x<='9';x=getchar()) sum=sum*10+x-'0';
    return f*sum;
}

#define M 200005
#define eps 1e-10
int n,w,h,e1,e2;

struct node {
    double l,r;
};

struct point {
    int t;
    double x,y;
    
    inline void in() {
        t=read(),x=read(),y=read();
    }
}p[M];

inline bool check(double v) {
    node a,t,tmp;
    a.l=a.r=e1;
    for(int i=1,las=0;i<=n;las=p[i].t,++i) {
        las=p[i].t-las;
        
        double k[4]={0,1-h/p[i-1].y,1-h/p[i].y,1-h/p[i-1].y};
        double b[4]={0,h*p[i-1].x/p[i-1].y-las*v,h*p[i].x/p[i].y,h*p[i-1].x/p[i-1].y+las*v};
        
        b[3]-=b[2],k[3]/=k[2],b[3]/=k[2];
        b[1]-=b[2],k[1]/=k[2],b[1]/=k[2];
        
        tmp.l=1e9,tmp.r=-1e9;
        
        t.l=max(a.l-las*v,k[3]*a.l+b[3]);
        t.r=min(a.l+las*v,k[1]*a.l+b[1]);
        if(t.l<t.r+eps) tmp.l=min(tmp.l,t.l),tmp.r=max(tmp.r,t.r);
        
        t.l=max(a.r-las*v,k[3]*a.r+b[3]);
        t.r=min(a.r+las*v,k[1]*a.r+b[1]);
        if(t.l<t.r+eps) tmp.l=min(tmp.l,t.l),tmp.r=max(tmp.r,t.r);
        
        if(k[3]!=1) {
            double x=(b[3]+las*v)/(1-k[3]);
            if(x>a.l&&x<a.r) {
                x-=las*v;
                tmp.l=min(tmp.l,x),tmp.r=max(tmp.r,x);
            }
            x=(las*v-b[3])/(k[3]-1);
            if(x>a.l&&x<a.r) {
                x+=las*v;
                tmp.l=min(tmp.l,x),tmp.r=max(tmp.r,x);
            }
        }
        if(k[1]!=1) {
            double x=(las*v-b[1])/(k[1]-1);
            if(x+eps>a.l&&x<a.r+eps) {
                x+=las*v;
                tmp.l=min(tmp.l,x),tmp.r=max(tmp.r,x);
            }
            x=(las*v+b[1])/(1-k[1]);
            if(x+eps>a.l&&x<a.r+eps) {
                x-=las*v;
                tmp.l=min(tmp.l,x),tmp.r=max(tmp.r,x);
            }
        }
        
        a=tmp;
        
        tmp.r=h*p[i].x/(h-p[i].y);
        tmp.l=(w*p[i].y-p[i].x*h)/(p[i].y-h);
        
        a.l=max(a.l,tmp.l);
        a.r=min(a.r,tmp.r);
        
        a.l=max(a.l,0),a.r=min(a.r,w);
        
        if(a.l>a.r+eps) return 0;
    }
    return 1;
}

int main () {
    //freopen("a.in","r",stdin);
    n=read(),w=read(),h=read(),e1=read(),e2=read();
    
    p[0].x=(e1+e2)/2.0,p[0].y=h/2.0;
    for1(1,n,i) p[i].in();
    
    double l=0,r=1e3+5,mid;
    for1(1,100,i) {
        mid=(l+r)/2;
        if(check(mid)) r=mid;
        else l=mid;
    }
    if(r>1000) puts("-1");
    else printf("%.10f
",r);
}
View Code
原文地址:https://www.cnblogs.com/asd123www/p/9843693.html