测试「20201104测试总结」
搜索大赛。
T1
令 \(\mathrm{dp}(a,b,x,y)\) 表示用了 \(a\) 个白棋,\(b\) 个黑棋,所得到的序列的所有后缀中白棋最多比黑棋多 \(x\) 个,黑棋最多比白棋多 \(y\) 个的方案数。
若放白棋,有:
\[\mathrm{dp}(a,b,x,y)=\mathrm{dp}(a+1,b,x+1,\max(0,y-1)),x<k,a<n
\]
若放黑棋,有:
\[\mathrm{dp}(a,b,x,y)=\mathrm{dp}(a,b+1,\max(0,x-1),y+1),y<k,b<m
\]
考试的时候有点昏,想到的是把后缀中两种棋子最大的差放进状态中,结果没有想出转移方程,还是打了暴力。
\(\text{Code}:\)
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long lxl;
const int maxn=155;
const lxl mod=1e9+7;
template <typename T>
inline void read(T &x)
{
x=0;T f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
x*=f;
}
int n,m,k;
int f[maxn][maxn][25][25];
int dp(int a,int b,int x,int y)
{
if(a==n&&b==m) return 1;
if(~f[a][b][x][y]) return f[a][b][x][y];
int res=0;
if(a<n&&x<k) (res+=dp(a+1,b,x+1,max(0,y-1)))%=mod;
if(b<m&&y<k) (res+=dp(a,b+1,max(0,x-1),y+1))%=mod;
return f[a][b][x][y]=res;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("chess.in","r",stdin);
freopen("chess.out","w",stdout);
#endif
read(n),read(m),read(k);
memset(f,-1,sizeof(f));
printf("%d\n",dp(0,0,0,0));
return 0;
}
T2
记忆化搜索。
毫无头绪,打了暴力。
\(\text{Code}:\)
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long lxl;
const int maxn=2001;
template <typename T>
inline void read(T &x)
{
x=0;T f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
x*=f;
}
int n,k;
int st[maxn],ed[maxn];
int ans=INF;
int f[11][maxn][11][11][11];
int dp(int pos,int now,int a,int b,int c)
{
if(~f[pos][now][a][b][c]) return f[pos][now][a][b][c];
int res=INF;
// 下一个人
if(a) res=min(res,dp(a,now,0,b,c)+abs(a-pos)+1);
if(b) res=min(res,dp(b,now,a,0,c)+abs(b-pos)+1);
if(c) res=min(res,dp(c,now,a,b,0)+abs(c-pos)+1);
if(now>n)
{
if(!a&&!b&&!c) return 0;
return f[pos][now][a][b][c]=res;
}
if(a&&b&&c) // 先接下一个人,再下一个人
{
res=min(res,dp(ed[now],now+1,a,b,c)+abs(pos-st[now])+abs(st[now]-ed[now])+2);
res=min(res,dp(a,now+1,ed[now],b,c)+abs(pos-st[now])+abs(a-st[now])+2);
res=min(res,dp(b,now+1,a,ed[now],c)+abs(pos-st[now])+abs(b-st[now])+2);
res=min(res,dp(c,now+1,a,b,ed[now])+abs(pos-st[now])+abs(c-st[now])+2);
}
else if(!a) // 直接接下一个人
res=min(res,dp(st[now],now+1,ed[now],b,c)+abs(pos-st[now])+1);
else if(!b)
res=min(res,dp(st[now],now+1,a,ed[now],c)+abs(pos-st[now])+1);
else
res=min(res,dp(st[now],now+1,a,b,ed[now])+abs(pos-st[now])+1);
return f[pos][now][a][b][c]=res;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("taxi.in","r",stdin);
freopen("taxi.out","w",stdout);
#endif
read(n),read(k);
for(int i=1;i<=n;++i)
read(st[i]),read(ed[i]);
memset(f,-1,sizeof(f));
printf("%d\n",dp(1,1,0,0,0));
return 0;
}
T3
折半搜索。
分别搜出前后两部分能组成哪些数,再二分查找最大能组成哪个数。
\(\text{Code}:\)
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <set>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long lxl;
const int maxn=1e6+5;
template <typename T>
inline void read(T &x)
{
x=0;T f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
x*=f;
}
int n,m,a[45];
set<int> s[2];
int ans;
void dfs(int x,int l,int r)
{
if(l>r) return s[r==n].insert(x),ans=max(ans,x),void();
dfs((x+a[l])%m,l+1,r);
dfs(x,l+1,r);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("stone.in","r",stdin);
freopen("stone.out","w",stdout);
#endif
read(n),read(m);
for(int i=1;i<=n;++i) read(a[i]),a[i]%=m;
dfs(0,1,n/2);
dfs(0,n/2+1,n);
for(set<int>::iterator it=s[0].begin();it!=s[0].end();++it)
{
ans=max(ans,(*it+*(--s[1].upper_bound(m-*it)))%m);
ans=max(ans,(*it+*(--s[1].upper_bound(2*m-*it)))%m);
}
printf("%d\n",ans);
return 0;
}
T4
神仙网络流。
将每个导弹能打到的点串起来,然后最小割。
\(\text{Code}:\)
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <queue>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long lxl;
const int maxn=55,maxm=2e5+5;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[1<<21],*p1=buf,*p2=buf;
template <typename T>
inline void read(T &x)
{
x=0;T f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
x*=f;
}
struct edge
{
int u,v,cp,next;
edge(int u,int v,int cp,int next)
:u(u),v(v),cp(cp),next(next){}
edge(){}
}e[maxm<<1];
int head[maxn*maxn<<1],ecnt;
inline void add(int u,int v,int cp)
{
e[ecnt]=edge(u,v,cp,head[u]);
head[u]=ecnt++;
e[ecnt]=edge(v,u,0,head[v]);
head[v]=ecnt++;
}
int n,m;
int wy[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
int G[maxn][maxn];
int s,t;
int d[maxn*maxn<<1],gap[maxn*maxn<<1],nxt[maxn*maxn<<1];
inline void bfs()
{
queue<int> q;
memset(d,0,sizeof(d));
memset(gap,0,sizeof(gap));
++gap[d[t]=1];
q.push(t);
while(!q.empty())
{
int u=q.front();q.pop();
nxt[u]=head[u];
for(int i=head[u];~i;i=e[i].next)
{
int v=e[i].v;
if(d[v]) continue;
++gap[d[v]=d[u]+1];
q.push(v);
}
}
}
int ISAP(int u,int flow)
{
if(u==t||!flow) return flow;
int rest=flow;
for(int &i=nxt[u];~i;i=e[i].next)
{
int v=e[i].v;
if(!e[i].cp||d[v]+1!=d[u]) continue;
int k=ISAP(v,min(e[i].cp,rest));
if(!k) continue;
e[i].cp-=k;
e[i^1].cp+=k;
rest-=k;
if(!rest) return flow;
}
nxt[u]=head[u];
if(!--gap[d[u]]) d[s]=t+1;
++gap[++d[u]];
return flow-rest;
}
inline int pos(int x,int y) {return (x-1)*m+y;}
int main()
{
#ifndef ONLINE_JUDGE
freopen("missile.in","r",stdin);
freopen("missile.out","w",stdout);
#endif
read(n),read(m);
memset(head,-1,sizeof(head));
s=1;t=n*m*2+2;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
{
read(G[i][j]);
add(pos(i,j)<<1,pos(i,j)<<1|1,INF);
}
int maxflow=0;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
{
if(G[i][j]>=0) continue;
int type=abs(G[i][j])-1;
if(type<=1) add(s,pos(i,j)<<1,INF);
else add(pos(i,j)<<1|1,t,INF);
int px=i,py=j,x=px+wy[type][0],y=py+wy[type][1];
if(x>n||x<1||y>m||y<1) continue;
int Max=0;
while(x<=n&&y<=m&&x>=1&&y>=1)
{
Max=max(Max,max(0,G[x][y]));
x+=wy[type][0];y+=wy[type][1];
}
x=px+wy[type][0],y=py+wy[type][1];
while(x<=n&&y<=m&&x>=1&&y>=1)
{
if(type<=1) add(pos(px,py)<<1,pos(x,y)<<1,Max-max(0,G[px][py]));
else add(pos(x,y)<<1|1,pos(px,py)<<1|1,Max-max(0,G[px][py]));
px+=wy[type][0];py+=wy[type][1];
x+=wy[type][0];y+=wy[type][1];
}
maxflow+=Max;
}
bfs();
while(d[s]<=t)
maxflow-=ISAP(s,1<<30);
printf("%d\n",maxflow);
return 0;
}