值得学习的递推思路
博弈论,本质是dp的状态转移
状态转移有规律,复制黏贴就搞定了
https://nanti.jisuanke.com/t/A2009
#include<bits/stdc++.h>
#define RD1(x) scanf("%d",&x)
#define RD2(x,y) scanf("%d %d",&x,&y)
#define RD3(x,y,z) scanf("%d %d %d",&x,&y,&z)
#define RDL1(x) scanf("%ulld",&x)
#define RDL2(x,y) scanf("%ulld %ulld",&x,&y)
#define RDL3(x,y,z) scanf("%ulld %ulld %ulld",&x,&y,&z)
#define CLR(x) memset(x,0,sizeof(x))
#define NEG(x) memset(x,0xff,sizeof(x))
#define maxm (1111+10)
#define maxn (1000+5)
#define lson (rt<<1)
#define rson (rt<<1|1)
#define mod (1000000007)
#define pi acos(-1)
#define eps 1e-14
#define acc ios::sync_with_stdio(false);cin.tie(0)
#define inf 0x3f3f3f3f
#define INF(x) memset(x,inf,sizeof(x))
#define CLRQ(Q) while(!(Q).empty())(Q).pop()
#define see(x) (cerr<<(#x)<<'='<<(x)<<' ')
#define NL printf("\n")
#define fi freopen("C:\\Users\\Administrator\\Desktop\\in","r",stdin)
#define fo freopen("C:\\Users\\Administrator\\Desktop\\out","w",stdout)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int n,m,k,l;
int dp[maxn][400];
int aa[maxn],bb[maxn],cc[maxn];
int main()
{
NEG(dp);
acc;cin>>n>>m>>k>>l;int zero=200;
for(int i=zero+k;i<=zero+100;i++)dp[n+1][i]=2;
for(int i=zero+l+1;i<zero+k;i++)dp[n+1][i]=1;
for(int i=zero-100;i<=zero+l;i++)dp[n+1][i]=0;
for(int i=1;i<=n;i++)cin>>aa[i]>>bb[i]>>cc[i];
int nxt;
for(int i=n;i;i--)
{
int a,b,c;a=aa[i],b=bb[i],c=cc[i];
if(i&1)for(int s=-100;s<=100;s++)
{
nxt=min(a+s,100);
if(a&&dp[i+1][zero+nxt]==2){dp[i][zero+s]=2;continue;}
nxt=max(-100,s-b);
if(b&&dp[i+1][zero+nxt]==2){dp[i][zero+s]=2;continue;}
nxt=-s;
if(c&&dp[i+1][zero+nxt]==2){dp[i][zero+s]=2;continue;}
nxt=min(a+s,100);
if(a&&dp[i+1][zero+nxt]==1){dp[i][zero+s]=1;continue;}
nxt=max(-100,s-b);
if(b&&dp[i+1][zero+nxt]==1){dp[i][zero+s]=1;continue;}
nxt=-s;
if(c&&dp[i+1][zero+nxt]==1){dp[i][zero+s]=1;continue;}
nxt=min(a+s,100);
if(a&&dp[i+1][zero+nxt]==0){dp[i][zero+s]=0;continue;}
nxt=max(-100,s-b);
if(b&&dp[i+1][zero+nxt]==0){dp[i][zero+s]=0;continue;}
nxt=-s;
if(c&&dp[i+1][zero+nxt]==0){dp[i][zero+s]=0;continue;}
}
else for(int s=-100;s<=100;s++)
{
nxt=min(a+s,100);
if(a&&dp[i+1][zero+nxt]==0){dp[i][zero+s]=0;continue;}
nxt=max(-100,s-b);
if(b&&dp[i+1][zero+nxt]==0){dp[i][zero+s]=0;continue;}
nxt=-s;
if(c&&dp[i+1][zero+nxt]==0){dp[i][zero+s]=0;continue;}
nxt=min(a+s,100);
if(a&&dp[i+1][zero+nxt]==1){dp[i][zero+s]=1;continue;}
nxt=max(-100,s-b);
if(b&&dp[i+1][zero+nxt]==1){dp[i][zero+s]=1;continue;}
nxt=-s;
if(c&&dp[i+1][zero+nxt]==1){dp[i][zero+s]=1;continue;}
nxt=min(a+s,100);
if(a&&dp[i+1][zero+nxt]==2){dp[i][zero+s]=2;continue;}
nxt=max(-100,s-b);
if(b&&dp[i+1][zero+nxt]==2){dp[i][zero+s]=2;continue;}
nxt=-s;
if(c&&dp[i+1][zero+nxt]==2){dp[i][zero+s]=2;continue;}
}
//for(int s=-100;s<=100;s++)see(i),see(s),see(dp[i][s+zero]),NL;
}
if(dp[1][m+zero]==2)cout<<"Good Ending";
else if(dp[1][m+zero]==1)cout<<"Normal Ending";
else cout<<"Bad Ending";
return 0;
} https://nanti.jisuanke.com/t/A2009
难在思维转换,一旦想到了,剩下的就是kruskal模板建图,询问时lca树上最短路
#include<bits/stdc++.h>
#define RD1(x) scanf("%d",&x)
#define RD2(x,y) scanf("%d %d",&x,&y)
#define RD3(x,y,z) scanf("%d %d %d",&x,&y,&z)
#define RDL1(x) scanf("%ulld",&x)
#define RDL2(x,y) scanf("%ulld %ulld",&x,&y)
#define RDL3(x,y,z) scanf("%ulld %ulld %ulld",&x,&y,&z)
#define CLR(x) memset(x,0,sizeof(x))
#define NEG(x) memset(x,0xff,sizeof(x))
#define maxm (1111+10)
#define maxn (500*500*2+5)
#define lson (rt<<1)
#define rson (rt<<1|1)
#define mod (1000000007)
#define pi acos(-1)
#define eps 1e-14
#define acc ios::sync_with_stdio(false);cin.tie(0)
#define inf 0x3f3f3f3f
#define INF(x) memset(x,inf,sizeof(x))
#define CLRQ(Q) while(!(Q).empty())(Q).pop()
#define see(x) (cerr<<(#x)<<'='<<(x)<<' ')
#define NL printf("\n")
#define fi freopen("C:\\Users\\Administrator\\Desktop\\in","r",stdin)
#define fo freopen("C:\\Users\\Administrator\\Desktop\\out","w",stdout)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int n,m;
int head[maxn],to[maxn],pre[maxn],tot1,dep[maxn];
int f[maxn][30];
void adde(int u,int v)
{
to[++tot1]=v,pre[tot1]=head[u],head[u]=tot1;
}
inline int tt(int x,int y)
{
return (x-1)*m+y;
}
struct E
{
int u,v,d;
}e[maxn];
bool operator<(E x,E y)
{
return x.d>y.d;
}
struct DS
{
int fa[maxn];
void init(int n)
{
for(int i=1;i<=n;i++)fa[i]=i;
}
int getf(int x)
{
return x==fa[x]?x:fa[x]=getf(fa[x]);
}
bool merg(int x,int y)
{
int p1=getf(x),p2=getf(y);
if(p1==p2)return 0;
fa[p2]=p1;return 1;
}
}ds;
void dfs(int u,int fa)
{
f[u][0]=fa;for(int i=1;i<=25;i++)f[u][i]=f[f[u][i-1]][i-1];
//see(u),see(fa),NL;
for(int i=head[u];i;i=pre[i])
{
int v=to[i];//see(u),see(v),NL;
if(v==fa)continue;
dep[v]=dep[u]+1;
dfs(v,u);
}
}
int lca(int x,int y)
{
if(dep[x]<dep[y])swap(x,y);
for(int i=25;i>=0;i--)if(dep[x]-(1<<i)>=dep[y])
x=f[x][i];
if(x==y)return x;
for(int i=25;i>=0;i--)if(f[x][i]!=f[y][i])
x=f[x][i],y=f[y][i];
return f[x][0];
}
int main()
{
acc;cin>>n>>m;
int tot=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
char c;int d;
cin>>c>>d;if(c=='D')
{
int u=tt(i,j),v=tt(i+1,j);
e[tot++]={u,v,d};
//see(u),see(v),NL;
//adde(tt(i,j),tt(i+1,j),d),adde(tt(i+1,j),tt(i,j),d);
}
cin>>c>>d;if(c=='R')
{
int u=tt(i,j),v=tt(i,j+1);
e[tot++]={u,v,d};
//see(u),see(v),NL;
//adde(tt(i,j+1),tt(i,j),d),adde(tt(i,j),tt(i,j+1),d);
}
}
sort(e,e+tot);
//see(tot);
ds.init(n*m);
int cnt=0;
for(int i=0;i<tot&&cnt<n*m-1;i++)
{
int u=e[i].u,v=e[i].v,d=e[i].d;
if(ds.merg(u,v))
{
//see(u),see(v),NL;
cnt++,adde(u,v),adde(v,u);
}
}
//see(tot1),NL;
dfs(1,0);
int q;cin>>q;while(q--)
{
int x,y,xx,yy;cin>>x>>y>>xx>>yy;
x=tt(x,y),y=tt(xx,yy);
//see(x),see(y),NL;
cout<<dep[x]+dep[y]-dep[lca(x,y)]*2<<endl;
}
return 0;
} https://ac.nowcoder.com/acm/contest/358/E
这两道应该是启发式合并入门题。多校里很多难题都由此衍生



京公网安备 11010502036488号