USACO ttwo 难度不大,挺适合练编码能力。一开始直接计算出了两个人的移动序列,但发现没有用。所以应该要用链表来存每个节点的后一个节点,然后进行枚举即可。
/*
ID: 13917981
PROG: ttwo
LANG: C++
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <ctime>
#include <vector>
#include <list>
#include <deque>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <algorithm>
#include <cmath>
#define REP(i,n) for(int i=0;i<(n);i++)
#define REP1(i,n) for(int i=1;i<=(n);i++)
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define CLR(x,n) memset(x,n,sizeof(x))
using namespace std;
/*
WA 一次 忘了输出0了..
*/
void setio(string name)
{
string in_f=name+".in";
string out_f=name+".out";
freopen(in_f.c_str(),"r",stdin);
freopen(out_f.c_str(),"w",stdout);
}
int gcd(int a,int b)
{return b==0?a:gcd(b,a%b);}
struct point{int x,y,dir;point(){x=y=dir=100;}};
char s[20][20];
int vis[2][20][20][4]; //方向 N 0 E 1 S 2 W 3
point next[2][20][20][4];int leng[2];
void get2(int x,int y,int dir,int &x1,int &y1)
{
if (dir==0){x1=x-1;y1=y;}
if (dir==1){x1=x;y1=y+1;}
if (dir==2){x1=x+1;y1=y;}
if (dir==3){x1=x;y1=y-1;}
}
bool out1(int x,int y)
{ return x<0 || x>9 || y<0 || y>9;}
void search1(int ty,int x,int y,int dir,int len)
{
//printf("%d %d %d %d %d\n",ty,x,y,dir,len);
vis[ty][x][y][dir]=1;
//path[ty][len][0]=x;path[ty][len][1]=y;
int x1=0,y1=0,x2=x,y2=y,dir2=dir;
get2(x,y,dir,x1,y1);
if (s[x1][y1]=='*' || out1(x1,y1))dir2=(dir+1)%4;
else {x2=x1;y2=y1;}
point& t=next[ty][x][y][dir];
t.x=x2;t.y=y2;t.dir=dir2;
if (vis[ty][x2][y2][dir2]){leng[ty]=len;return;}
//printf("%d %d %d %d %d %d %d\n",ty,x,y,dir,t.x,t.y,t.dir);
search1(ty,x2,y2,dir2,len+1);
}
char get1()
{char c;do c=getchar();while(!(c=='.'||c=='*'||c=='C'||c=='F'));return c;}
int main()
{
setio("ttwo");
int fx,fy,cx,cy;
REP(i,10)REP(j,10) {
s[i][j]=get1();
if (s[i][j]=='F'){fx=i;fy=j;}
if (s[i][j]=='C'){cx=i;cy=j;}
}
//REP(i,10){REP(j,10)printf("%c ",s[i][j]);cout<<endl;}
CLR(vis,0);
search1(0,fx,fy,0,0);
search1(1,cx,cy,0,0);
point i=next[0][fx][fy][0];//printf("%d %d %d %d %d",fx,fy,i.x,i.y,i.dir);
point j=next[1][cx][cy][0];
//printf("%d %d\n",leng[0],leng[1]);
REP(ka,leng[0]*leng[1]/gcd(leng[0],leng[1]))
{
//printf("%d %d %d %d %d %d %d\n",ka,i.x,i.y,i.dir,j.x,j.y,j.dir);
if (i.x==j.x && i.y==j.y){printf("%d\n",ka+1);return 0;}
i=next[0][i.x][i.y][i.dir];
j=next[1][j.x][j.y][j.dir];
}
cout<<0<<endl;
return 0;
//system("pause");
}
BZOJ 1625 容易上当的一道题。因为休息必须要恢复到不疲劳才能继续运动,我理解成了随时休息随时继续。接下来就是dp,设d[i]是第i天时不疲劳情况下答案的最大值,则枚举休息的天数即可d[i]=d[i-2k] + a[i-2k]+..a[i-k-1] 再利用前缀和优化时间
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <ctime>
#include <cmath>
#include <vector>
#include <deque>
#include <algorithm>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <stack>
#define REP(i,n) for(int i=0;i<(n);i++)
#define REP1(i,n) for(int i=1;i<=(n);i++)
#define FOR(i,a,b) for (int i=(a);i<=(b);i++)
#define CLR(x,n) memset(x,n,sizeof(x))
using namespace std;
int v[4000],w[4000],dp[15000];
int main()
{
int n,m;scanf("%d%d",&n,&m);
REP1(i,n)scanf("%d%d",&w[i],&v[i]);
CLR(dp,0);
REP1(i,n) for (int j=m;j>=1;j--)
{
if (j>=w[i]) dp[j]=max( dp[j], dp[j-w[i]]+v[i] );
}
printf("%d\n",dp[m]);
//REP1(i,n) {REP1(j,m)printf("%d ",dp[j]);cout<<endl;}
//system("pause");
return 0;
}