AtCoder Grand Contest 027题解

被暴虐,还是自己太弱了。

有一定影响是因为自己太想打一个好名次了,很多idea没有经过深入的思考就去实现。

好几次都是因为错误的思路浪费了一些时间。

但是主要还是自己的实力不太够。

B - Garbage Collector

一开始猜了一个连续段的性质,wa了。

然后考虑枚举我们最后走了几次,然后从后往前贪心。

假设我们枚举到了i,那么显然i要选择一个$cnt$最小的。

这里随便选一个就好了,因为首先i这里的$cnt$一定是$min+1$了。

并且所有$cnt$为$min$的点也一定要走回去,所以都是$-dis[i]*(cnt+1)^2+dis[i]*(cnt+2)^2$。

这样就可以做到$O(n^2)$了。

然后我感觉这是一个单峰的函数,然后就A了。$O(n*logn)$

#include <bits/stdc++.h>
#define int long long
#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 2000005
int n,K;
int a[M],pos[M];

map <int,ll> st;

inline ll calc_(int x) {
    if(st.count(x)) return st[x];
    ll num=0;
    for1(1,x,i) pos[n-i+1]=1,num+=K+a[n-i+1];
    int head=n;
    FOR2(n-x,1,i) {
        num+=1ll*(a[head]-a[i])*(pos[head]+1)*(pos[head]+1)+K;
        pos[i]=pos[head]+1;
        --head;
    }
    while (head) num+=1ll*a[head]*(pos[head]+1)*(pos[head]+1),--head;
    return st[x]=num+1ll*K*x;
}

signed main () {
    //freopen("a.in","r",stdin);
    n=read(),K=read();
    for1(1,n,i) a[i]=read();
    ll ans=8e18;
    int l=1,r=n,mid,midd;
    while (l+6<r) {
        mid=l+r>>1;
        midd=mid+r>>1;
        ll t[2]={calc_(mid),calc_(midd)};
        if(t[0]<t[1]) ans=min(ans,t[0]),r=midd;
        else ans=min(ans,t[1]),l=mid;
    }
    for1(l,r,i) {
        ll num=calc_(i);
        ans=min(ans,num);
    }
    //cout<<(double)clock()/CLOCKS_PER_SEC<<endl;
    cout<<ans<<endl;
}

C - ABland Yard

考试就卡在这里了。。

比较重要的信息就是无向图了。

自己画一下图就发现其实需要一个$AABBAABB......$是显然的。

然后我就不知道怎么判了。。。

看了一发别人的代码,感觉真的很6。

大概就是搞成一个二分图的样子。然后就直接判环就好了。

#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 1000005
int n,m;
char s[M];
int e_size,head[M],vis[M];

struct node {int v,nxt;}e[M*2];

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

inline void dfs(int x) {
    vis[x]=1;
    for(int i=head[x];i;i=e[i].nxt) {
        int v=e[i].v;
        if(vis[v]==1) {
            puts("Yes");
            exit(0);
        }
        if(vis[v]==0) dfs(v);
     }
     vis[x]=-1;
}

int main () {
//    freopen("a.in","r",stdin);
    n=read(),m=read();
    scanf("%s",s+1);
    for1(1,m,i) {
        int x=read(),y=read();
        if(s[x]==s[y]) e_add(x,y+n),e_add(y,x+n);
        else e_add(x+n,y),e_add(y+n,x);
    }
    for1(1,n,i) if(!vis[i]) dfs(i);
    puts("No");
}

D - Modulo Matrix

感觉好6。。。

我甚至连求周围点的$Lcm$都没想到。

一直以为真的会存在有大于有小于的情况的通解。。

正解思路就是黑白染色之后给黑色全部赋值,然后白色是周围点权值的$Lcm$。

现在的难题就是怎么构造使得$Lcm$在1e15的范围之内。

我想了一些比较蠢的,比如筛出来$n^2/2$个素数。。。。

还有就是找一个数的因子个数大于$n^2/2$。。。

其实是爆范围,而且还可能重的。

正解就是利用小的素数,然后分别以$i+j$和$i-j$分类,每一类乘上一个相同的质数。

我把$i+j$分了前n个,$i-j$分了后n个,这样就不会重了。

这样的构造使得$Lcm$只是4个素数的乘积,而且保证了两两不同。注意特判$n=2$。

#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 505
#define N 8000
int n;
ll a[M][M];
int prime[N+5];
bool notprime[N+5];

map <ll,bool> cc;

void get_prime() {
    for1(2,N,i) {
        if(!notprime[i]) prime[++prime[0]]=i;
        for1(1,prime[0],j) {
            if(i*prime[j]>N) break;
            notprime[i*prime[j]]=1;
            if(!(i%prime[j])) break;
        }
    }
}

inline ll gcd(ll x,ll y) {return y?gcd(y,x%y):x;}
inline ll Lcm(ll x,ll y) {return x/gcd(x,y)*y;}

int main () {
    //freopen("a.in","r",stdin);
    n=read();
    if(n==2) {
        puts("4 7");
        puts("23 10");
        return 0;
    }
    get_prime();
    for1(0,n+1,i) for1(0,n+1,j) a[i][j]=1;
    for1(1,n,i) for1(1,n,j) if(!(i+j&1)) a[i][j]=prime[(i+j)/2]*prime[1000-(i-j)/2-(n+1)/2+1];
    for1(1,n,i) for1(1,n,j) if(i+j&1) a[i][j]=Lcm(Lcm(a[i-1][j],a[i][j-1]),Lcm(a[i][j+1],a[i+1][j]))+1;
    for1(1,n,i) {
        for1(1,n,j) printf("%lld ",a[i][j]);
        puts("");
    }
}

E - ABBreviate

好神啊。

首先定义了$a=1,b=2$。然后我们发现在模3的情况下所有的变换都是相等的。

性质:一个$string$ $a$能变成$char$ $c$的条件是$val[a]==val[c]$并且$a$中有一个可以变换的位置。

我们只需要证明$a$的变换过程中可以不经过$ababa......$这种情况就行了。

画一画发现如果我们走到了这种情况我们是可以在上一步的位置改变走法的。

然后如果可以到达一个字符串就把它在原序列上划分区间(从左开始右端点最靠左)。

然后最后剩下的直接并给最后一个区间就好了,这样显然是不会重复的。

因为不会出现这个区间变成a,而划分是$ababa$的情况(这样就不是最靠左了)。

所以对于每种情况都是可达的。

#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;

#define M 100005
#define mod 1000000007
int n;
int f[M];
char a[M];
inline void inc(int &x,int y) {x+=y,x-=x>=mod?mod:0;}

int main () {
    //freopen("a.in","r",stdin);
    scanf("%s",a+1);
    n=strlen(a+1);
    bool t=0;
    for1(1,n-1,i) if(a[i]==a[i+1]) {t=1;break;}
    if(!t) return puts("1"),0;
    int ans=0;
    int s=0,pre[3]={0,-1,-1};
    f[0]=1;
    for1(1,n,i) {
        s=(s+2-(a[i]=='a'))%3;
        if(!s&&i<n) f[i]=1;
        ++s,s%=3;
        if(pre[s]!=-1) inc(f[i],f[pre[s]]);
        ++s,s%=3;
        if(pre[s]!=-1) inc(f[i],f[pre[s]]);
        ++s,s%=3;
        pre[s]=i;
    }
    cout<<f[n]<<endl;
}

F - Grafting

好坑啊,怎么感觉这个题比前三个要简单啊。。

一开始也是想不出来什么,但是仔细想想其实无法操作的原因就是我们没有一个固定的根!

如果我们有了一个根,显然剩下的点只能依次连到第二棵树上的$father$了。

这样就好说了,直接枚举第一次移动,然后将那个黑点作为根就可以做了。

$O(T*n^4)$

#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 55
int n;
int du[M];
bool vis[M],re[M];
int e_size,head[M],fa[M],pre[M];
struct node {
    int x,y;
    
    inline void in() {
        x=read(),y=read();
        if(x>y) swap(x,y);
    }
    inline bool operator <(const node &a) const {
        if(x!=a.x) return x<a.x;
        return y<a.y;
    }
}a[M],b[M];

struct edge {int v,nxt;}e[M*2];

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

inline bool check() {
    for1(1,n-1,i) if(a[i].x!=b[i].x||a[i].y!=b[i].y) return 0;
    return 1;
}

inline void dfs1(int x,int *ha) {
    for(int i=head[x];i;i=e[i].nxt) {
        int v=e[i].v;
        if(v==ha[x]) continue;
        ha[v]=x,dfs1(v,ha);
    }
}

inline void dfs2(int x) {
    vis[x]=1;
    for(int i=head[x];i;i=e[i].nxt) {
        int v=e[i].v;
        if(v==pre[x]||fa[v]!=x) continue;
        dfs2(v);
    }
}

inline int calc_(int x,int y) {
    e_size=0;
    memset(re,0,sizeof(re));
    memset(du,0,sizeof(du));
    memset(vis,0,sizeof(vis));
    memset(pre,0,sizeof(pre));
    memset(head,0,sizeof(head));
    re[x]=1;
    ++du[x],++du[y];
    e_add(x,y),e_add(y,x);
    for1(1,n-1,i) {
        int u=a[i].x;
        int v=a[i].y;
        if(u==x||v==x) continue;
        ++du[u],++du[v];
        e_add(u,v),e_add(v,u);
    }
    dfs1(x,pre),dfs2(x);
    int cnt=0,now=0;
    for1(1,n,i) now+=vis[i];
    cnt=now;
    while (now!=n) {
        int pos=0;
        for1(1,n,i) if(!vis[i]&&vis[fa[i]]&&!re[i]&&du[i]==1) {pos=i;break;}
        if(!pos) break;
        re[pos]=vis[pos]=1,++now;
        --du[pre[pos]],++du[fa[pos]];
    }
    return now==n?n-cnt+1:1e9;
}

int main () {
//    freopen("a.in","r",stdin);
    int Test_=read();
    while (Test_--) {
        n=read();
        for1(1,n-1,i) a[i].in();
        for1(1,n-1,i) b[i].in();
        sort(a+1,a+n),sort(b+1,b+n);
        
        if(check()) puts("0");
        else {
            int shu[M]={0};
            for1(1,n-1,i) ++shu[a[i].x],++shu[a[i].y];
            int ans=1e9;
            for1(1,n,i) if(shu[i]==1) {
                e_size=0;
                memset(fa,0,sizeof(fa));
                memset(head,0,sizeof(head));
                for1(1,n-1,j) e_add(b[j].x,b[j].y),e_add(b[j].y,b[j].x);
                dfs1(i,fa);
                for1(1,n,j) if(i!=j) {
                    int num=calc_(i,j);
                    ans=min(ans,num);
                }
            }
            if(ans==1e9) ans=-1;
            printf("%d\n",ans);
        }
    }
}
posted @ 2018-09-18 20:43  asd123www  阅读(293)  评论(0编辑  收藏  举报