神奇的幻方
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
",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-psim i}=B_{j-psim j}),(f_{i,j,k}+=sumlimits_{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);
}