jzoj2017-8-18提高组ANOIP模拟赛

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jzoj2017-8-18提高组ANOIP模拟赛相关的知识,希望对你有一定的参考价值。

太菜了,于是打算做做NOIP的题。

第一题:jzoj5305 C

一个仙人掌的路径方案计数。可以考虑到一个仙人掌路径出现多种情况的唯一可能是经过了一个环,而一个环的走法无非是走上或者走下。

因此随意Tarjan缩个点,然后仙人掌就被缩成了树,在这个树上跑一下倍增即可。

#include<bits/stdc++.h>
const int N=2e5+5;
const int M=6*1e5+5;
const int yql=1e9+7;
using namespace std;
int low[N],dfn[N],cnt=0,head[N],tot=0;
struct Edge{int u,v,next;}G[M],T[M];
stack<int> st;
int n,m;
int fa[N],dep[N],anc[18][N],bin[20],scnt=0,scc[N],vis[N],c[N],lim=0;
inline void addedge(int u,int v){
    G[++tot].u=u;G[tot].v=v;G[tot].next=head[u];head[u]=tot;
    G[++tot].u=v;G[tot].v=u;G[tot].next=head[v];head[v]=tot;
}
inline int read(){
    int f=1,x=0;char ch;
    do{ch=getchar();if(ch==-)f=-1;}while(ch<0||ch>9);
    do{x=x*10+ch-0;ch=getchar();}while(ch>=0&&ch<=9);
    return f*x;
}
inline void Tarjan(int u,int f){
    dfn[u]=low[u]=++cnt;st.push(u);
    vis[u]=1;
    for(int i=head[u];i;i=G[i].next){
        int v=G[i].v;if(v==f)continue;
        if(!dfn[v]){Tarjan(v,u);low[u]=min(low[u],low[v]);}
        else if(vis[v])low[u]=min(low[u],dfn[v]);
    }
    if(dfn[u]==low[u]){
        int cur=st.top();c[u]=cur!=u;
        while(st.top()!=u)scc[st.top()]=u,vis[st.top()]=0,st.pop();
        scc[st.top()]=u;vis[st.top()]=0;st.pop();
    }
}
inline void dfs(int u,int f){
    dfn[u]=1;c[u]+=c[f];
    dep[u]=dep[f]+1;
    anc[0][u]=f;
    for(int i=head[u];i;i=G[i].next)if(G[i].v!=f&&!dfn[G[i].v])dfs(G[i].v,u);
}
inline int calc(int u,int v){
    if(dep[u]<dep[v])swap(u,v);
    int x=u,y=v;
    for(int i=lim;i>=0;i--)if(dep[anc[i][u]]>=dep[v])u=anc[i][u];
    if(u==v)return bin[c[x]-c[anc[0][y]]];
    for(int i=lim;i>=0;i--)if(anc[i][u]!=anc[i][v])u=anc[i][u],v=anc[i][v];
    return bin[c[x]+c[y]-c[anc[0][u]]-c[anc[1][u]]];
}
int main(){
    bin[0]=1;
    n=read();m=read();
    for(int i=1;i<=20;i++)bin[i]=(bin[i-1]*2)%yql;
    for(int i=1;i<=m;i++){
        T[i].u=read();T[i].v=read();
        addedge(T[i].u,T[i].v);
        addedge(T[i].v,T[i].u);
    }
    for(int i=1;i<=n;i++)if(!dfn[i])Tarjan(i,0);
    tot=0;
    memset(head,0,sizeof(head));for(int i=1;i<=n;i++)dfn[i]=0;
    for(int i=1;i<=m;i++)if(scc[T[i].u]!=scc[T[i].v]){
        addedge(scc[T[i].u],scc[T[i].v]);addedge(scc[T[i].v],scc[T[i].u]);
    }
    for(int i=1;i<=n;i++)if(!dfn[i])dfs(i,0);
    lim=(int)(log(n)/log(2));
    for(int j=1;j<=lim;j++)for(int i=1;i<=n;i++)anc[j][i]=anc[j-1][anc[j-1][i]];
    int q=read();
    while(q--){
        int u=read(),v=read();
        printf("%d\n",calc(scc[u],scc[v]));
    }
}

第二题:jzoj5306 棋盘游戏

考虑到行列是独立的,这就是一个威佐夫博弈的裸题。

所以根据威佐夫博弈的公式算出delta*.618,如果=x先手必输,反之必胜。

#include<bits/stdc++.h>
using namespace std;
int x,y;
inline int read(){
    int f=1,x=0;char ch;
    do{ch=getchar();if(ch==-)f=-1;}while(ch<0||ch>9);
    do{x=x*10+ch-0;ch=getchar();}while(ch>=0&&ch<=9);
    return f*x;
}
inline int calc(int x,int y){
    if(x>y)swap(x,y);
    int ans=floor((1.0+sqrt(5.0))/2*(y-x));
    return ans;
}
int main(){
    int T=read();
    while(T--){
        int x=read(),y=read();
        int ans=calc(x,y);
        if(ans==x)puts("Alphago");else puts("Amphetamine");
    }
}

第三题:jzoj5307偷窃,bzoj4950(WF2017)

这就是Claris在51nod讲过的wf原题,考虑下最大值一行仅需要留一个,约束关系形成二分图的关系,跑一下最大匹配即可。

#include<bits/stdc++.h>
const int N=110;
const int M=10010;
using namespace std;
typedef long long ll;
ll ans=0;
int a[N][N];
int n,m;
int head[M],tot=0,vis[N],f[M],m1[N],m2[N];
struct Edge{int u,v,next;}G[M<<1];
inline void addedge(int u,int v){
    G[++tot].u=u;G[tot].v=v;G[tot].next=head[u];head[u]=tot;
}
inline int read(){
    int f=1,x=0;char ch;
    do{ch=getchar();if(ch==-)f=-1;}while(ch<0||ch>9);
    do{x=x*10+ch-0;ch=getchar();}while(ch>=0&&ch<=9);
    return f*x;
}
inline int dfs(int u){
    for(int i=head[u];i;i=G[i].next){
        int v=G[i].v;if(vis[v])continue;
        vis[v]=1;
        if(!f[v]||dfs(f[v])){f[v]=u;return 1;}
    }
    return 0;
}
int main(){
    n=read();m=read();ans=0;
    for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){
        a[i][j]=read();m1[i]=max(m1[i],a[i][j]);m2[j]=max(m2[j],a[i][j]);
        ans+=a[i][j];
    }
    for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)if(a[i][j]){
        --ans;if(m1[i]>1&&m1[i]==m2[j])addedge(i,j);
    }
    for(int i=1;i<=n;i++)if(m1[i])ans-=m1[i]-1;
    for(int i=1;i<=m;i++)if(m2[i])ans-=m2[i]-1;
    for(int i=1;i<=n;i++)if(m1[i]){
        memset(vis,0,sizeof(vis));
        ans+=dfs(i)*(m1[i]-1);
    }
    cout<<ans<<endl;
}

 

以上是关于jzoj2017-8-18提高组ANOIP模拟赛的主要内容,如果未能解决你的问题,请参考以下文章

jzoj6276. noip提高组模拟1树

[jzoj 5770]2018提高组模拟A组8.6可爱精灵宝贝 (区间dp)

2018.8.7提高B组模拟考试

2018.8.10提高B组模拟考试

2018.8.9提高B组模拟考试

2018.8.6提高A组模拟考试