NOIP2015

神奇的幻方

Link
模拟。

#include<iostream> 
using namespace std;
int a[40][40];
int main()
{
    register int n,s=1,x,y;
    cin>>n;            
    while(s<=n*n)
        if(s==1) a[x=1][y=n+1>>1]=s++;
        else if(x==1&&y!=n) a[x=n][++y]=s++;
	else if(x!=1&&y==n) a[--x][y=1]=s++;
	else if(x==1&&y==n) a[++x][y]=s++;
	else if(x!=1&&y!=n)
	    if(!a[x-1][y+1]) a[--x][++y]=s++;
	    else a[++x][y]=s++;
    for(int i=1;i<=n;++i,cout<<endl) for(int j=1;j<=n;++j) cout<<a[i][j]<<' ';
    return 0;
}

信息传递

Link
并查集求最小环。
记录父亲的同时记录到根的长度,若一条边两端属于同一集合则更新最小环长度。

#include<bits/stdc++.h>
using namespace std;
int read(){int x;scanf("%d",&x);return x;}
const int N=200007;
int ans=1e9,d[N],fa[N];
int Find(int x)
{
    if(x^fa[x])
    {
	int f=fa[x];
	fa[x]=Find(fa[x]),d[x]+=d[f];
    }
    return fa[x];
}
void check(int u,int v)
{
    int x=Find(u),y=Find(v);
    if(x^y) fa[x]=y,d[u]=d[v]+1; else ans=min(ans,d[u]+d[v]+1);
}
int main()
{
    int n=read(),i;
    for(i=1;i<=n;++i) fa[i]=i;
    for(i=1;i<=n;++i) check(i,read());
    printf("%d",ans);
}

斗地主

Link
dp预处理除了顺子以外的情况。(注意可以拆牌)
然后暴力搜索顺子。

#include<cstdio>
#include<cstring>
void min(int &a,int b){a=a<b? a:b;}
int a[16],f[16][16][16][16][3],cnt[6],ans;
void dp()
{
    memset(f,0x3f,sizeof f),f[0][0][0][0][0]=0;
    for(int o=0,i,j,k,l,x;o<=13;++o)
	for(k=0;k<=13;++k)
	    for(i=0;i<=13;++i)
		for(j=0;j<=13;++j)
		    for(l=0;l<=2;++l)
		    {
			x=100;
			if(i>0) min(x,f[i-1][j][k][o][l]+1);
                        if(j>0) min(x,f[i][j-1][k][o][l]+1);
                        if(k>0) min(x,f[i][j][k-1][o][l]+1);
                        if(o>0) min(x,f[i][j][k][o-1][l]+1);
                        if(l>0) min(x,f[i][j][k][o][l-1]+1);
                        if(l>1) min(x,f[i][j][k][o][l-2]+1);
			if(i>0&&k>0) min(x,f[i-1][j][k-1][o][l]+1);
			if(l>0&&k>0) min(x,f[i][j][k-1][o][l-1]+1);
			if(j>0&&k>0) min(x,f[i][j-1][k-1][o][l]+1);
			if(i>1&&o>0) min(x,f[i-2][j][k][o-1][l]+1);
                        if(i>0&&o>0&&l>0) min(x,f[i-1][j][k][o-1][l-1]+1);
                        if(o>0&&l>1) min(x,f[i][j][k][o-1][l-2]+1);
                        if(j>0&&o>0) min(x,f[i][j-1][k][o-1][l]+1);
                        if(j>1&&o>0) min(x,f[i][j-2][k][o-1][l]+1);
                        if(o>1) min(x,f[i][j][k][o-2][l]+1);
			if(o>0) min(x,f[i+1][j][k+1][o-1][l]);
                        if(k>0) min(x,f[i+1][j+1][k-1][o][l]);
			min(f[i][j][k][o][l],x);
		    }
}
void dfs(int x)
{
    if(x>=ans) return;
    for(int k=1,i,j,f,c;k<=3;++k)
        for(i=1;i<=12;++i)
        {
            f=1; if(k==1) c=5; else c=5-k;
            while(f&&i+c-1<=12)
            {
                for(j=1;j<=c;++j) if(a[i+j-1]<k){f=0;break;}
                if(!f) continue;
                for(j=1;j<=c;++j) a[i+j-1]-=k;
                dfs(x+1);
                for(j=1;j<=c;++j) a[i+j-1]+=k;
                ++c;
            }
        }
    memset(cnt,0,sizeof cnt);
    for(int i=1;i<=13;++i) ++cnt[a[i]];
    cnt[5]=a[14],min(ans,x+f[cnt[1]][cnt[2]][cnt[3]][cnt[4]][cnt[5]]);
}
int main()
{
    int n,T;scanf("%d%d",&T,&n),dp();
    for(int num,col,i;T;--T)
    {
        memset(a,0,sizeof a),ans=n;
        for(i=1;i<=n;++i)
        {
            scanf("%d%d",&num,&col);
            if(!num) ++a[14];
            if(num>=3) ++a[num-2];
            if(num==1) ++a[12];
            if(num==2) ++a[13];
        }
        dfs(0),printf("%d\n",ans);
    }
    return 0;
}

跳石头

Link
二分答案。

#include<bits/stdc++.h>
using namespace std;
int a[100002],d,n,m,l,r,mid,ans;
int read(){int x;scanf("%d",&x);return x;}
int check(int x)
{
    int num=0,now=0;
    for(int i=1;i<n+2;++i) if(a[i]-a[now]<x) ++num; else now=i;
    return num<=m;
}
int main()
{
    d=read(),n=read(),m=read();
    for(int i=1;i<=n;i++) a[i]=read();
    a[n+1]=d,l=1,r=d;
    while(l<=r) mid=(l+r)>>1,check(mid)? ans=mid,l=mid+1:r=mid-1;
    cout<<ans;
    return 0;
}

子串

Link
\(f_{i,j,k}\)表示考虑\(A\)的前\(i\)位,用\(k\)个串匹配到了\(B\)的第\(j\)位。
那么首先有\(f_{i,j,k}=f_{i-1,j,k}\)
然后找到最小的\(p\)满足\(A_{i-p\sim i}=B_{j-p\sim j}\)\(f_{i,j,k}+=\sum\limits_{o=1}^pf_{i-o,j-o,k-1}\)
前缀和优化即可。

#include<cstdio>
int f[201][201],sum[201][201],P=1000000007;char a[1001],b[201];
int inc(int a,int b){return a+=b,a>=P? a-P:a;}
int main()
{
    int n,m,K,i,j,k;
    scanf("%d%d%d%s%s",&n,&m,&K,a+1,b+1),f[0][0]=1;
    for(i=1;i<=n;++i) for(j=m;j;--j) for(k=K;k;--k) f[j][k]=inc(f[j][k],sum[j][k]=a[i]==b[j]? inc(sum[j-1][k],f[j-1][k-1]):0);
    printf("%d",f[m][K]);
}

运输计划

Link
二分一个\(lim\),然后对于所有路径长度\(>lim\)的计划,我们需要把它的路径上的一条边边权改为\(0\)
可以通过差分将这条链上的点(\(lca\)除外)全部\(+1\),然后dfs的时候还原,如果某个点的值等于需要改边的路径条数,那么说明所有路径都经过这个点到它父亲的那条边。
根据贪心,我们选择这些边中边权最大的边一定是最优的。
然后判断最长路径\(-\)上述边中的最大边权是否\(\le lim\)即可。

#include<bits/stdc++.h>
#define pi pair<int,int>
#define pb push_back
using namespace std;
namespace IO
{
    char ibuf[(1<<21)+1],*iS,*iT ;
    char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);}
    int read(){int x=0,c=Get();while(!isdigit(c))c=Get();while(isdigit(c))x=x*10+c-48,c=Get();return x;}
}
using namespace IO;
int max(int a,int b){return a>b? a:b;}
const int N=300007;
vector<pi>E[N];int n,m,mx,cnt,x,top[N],dis[N],sz[N],son[N],fa[N],d[N],dep[N],t[N];
struct query{int u,v,l,lca;}q[N];
void dfs(int u,int f)
{
    fa[u]=f,sz[u]=1,dep[u]=dep[f]+1,dis[u]=dis[f]+d[u];
    for(auto[v,w]:E[u]) if(v^f) d[v]=w,dfs(v,u),sz[u]+=sz[v],son[u]=sz[v]>sz[son[u]]? v:son[u];
}
void Dfs(int u,int tp){top[u]=tp;if(son[u])Dfs(son[u],tp);for(auto[v,w]:E[u]) if(v^fa[u]&&v^son[u]) Dfs(v,v);}
int lca(int u,int v){while(top[u]^top[v]) dep[top[u]]>dep[top[v]]? u=fa[top[u]]:v=fa[top[v]];return dep[u]<dep[v]? u:v;}
void cal(int u)
{
    for(auto[v,w]:E[u]) if(v^fa[u]) cal(v),t[u]+=t[v];
    if(t[u]==cnt) x=max(x,d[u]);
}
int check(int lim)
{
    memset(t,0,sizeof t),cnt=x=0;
    for(int i=1;i<=m;++i) if(q[i].l>lim) ++t[q[i].u],++t[q[i].v],t[q[i].lca]-=2,++cnt;
    cal(1);
    return mx-x<=lim;
}
int main()
{
    n=read(),m=read();
    for(int i=1,u,v,w;i<n;++i) u=read(),v=read(),w=read(),E[u].pb(pi(v,w)),E[v].pb(pi(u,w));
    dfs(1,0),Dfs(1,1);
    for(int i=1;i<=m;++i) q[i].u=read(),q[i].v=read(),q[i].lca=lca(q[i].u,q[i].v),mx=max(mx,q[i].l=dis[q[i].u]+dis[q[i].v]-dis[q[i].lca]*2);
    int l=0,r=mx,mid;
    while(l<=r) mid=l+r>>1,check(mid)? r=mid-1:l=mid+1;
    printf("%d",l);
}
posted @ 2019-11-14 20:03  Shiina_Mashiro  阅读(133)  评论(0编辑  收藏  举报