JZOJ NO.1 【2012.02.25普及组】牛车
题目
这道题就是同车道前面有x头牛,车速降低D*X,低于最低限速不允许,一共可以有多少辆车
代码
#include <cstdio>
using namespace std;
int a[1000001],n,ans,x,maxn,u,m,d,l,e;
int max(int a,int b){return (a>b)?a:b;}
int main(){
scanf("%d%d%d%d",&n,&m,&d,&l);
for (int i=1;i<=n;i++){
scanf("%d",&x);
if (x>=l){
a[(x-l)/d+1]++; //最少要插到第几行
maxn=max(maxn,(x-l)/d+1);//桶排
}
} e=m;
for (int i=1;i<=maxn;i++){
if (a[i]==0){e+=m;continue;}//可以增加内存
if (a[i]<=e) {ans+=a[i];e-=a[i];}//可以插入
else {ans+=e;e=0;} //最多插完内存
e+=m;//为下一行增加内存
}
printf("%d",ans);
return 0;
}
JZOJ NO.2 【2012.02.25普及组】危险系数
分析
就是求它的最短路径,不多解释。
代码
#include <cstdio>
#include <algorithm>
using namespace std;
int n,m,a[10001],f[101][101],ans;
int main(){
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++) scanf("%d",&a[i]);
for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) scanf("%d",&f[i][j]);
for (int k=1;k<=n;k++)
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if (i!=j&&i!=k&&j!=k) f[i][j]=min(f[i][j],f[i][k]+f[k][j]);//floyd
for (int i=1;i<=m-1;i++) ans+=f[a[i]][a[i+1]];
printf("%d",ans); return 0;
}
JZOJ NO.3 【普及模拟】前缀转后缀
分析
模拟建树,再用后序遍历输出。
代码
#include <cstdio>
#include <cctype>
using namespace std;
struct z{int lson,rson;}tree[201];
int n,m; char c[201],w;
int build(int x){
m++;
if (isdigit(c[x])){tree[x].lson=-1;tree[x].rson=-1;return x;}//是数字
else {tree[x].lson=build(m+1); tree[x].rson=build(m+1);return x;}//是符号
}
void print(int x){
if (tree[x].lson!=-1) print(tree[x].lson);//有左孩子
if (tree[x].rson!=-1) print(tree[x].rson);//有右孩子
printf("%c ",c[x]);
}
int main(){
freopen("j4.in","r",stdin);
freopen("j4.out","w",stdout);
while ((c[++n]=getchar())!='\n'){
w=getchar();
if (w=='\n') break;} n--;
build(1);//建树
print(1);//输出
return 0;
}
JZOJ NO.4 【普及模拟】游戏
首先先放记忆化搜索的代码。
#include <cstdio>
using namespace std;
const int q[5][4]={{2,1,0,2},{1,1,1,1},{0,0,2,1},{0,3,0,0},{1,0,0,1}};
int n,a,b,c,d,f[61][61][61][61];
int dfs(int a,int b,int c,int d){
if (f[a][b][c][d]) return f[a][b][c][d];//有值说明已经搜过了
for (int i=0;i<=4;i++)
if (a-q[i][0]>=0&&b-q[i][1]>=0&&c-q[i][2]>=0&&d-q[i][3]>=0){
if (dfs(a-q[i][0],b-q[i][1],c-q[i][2],d-q[i][3])==2) return f[a][b][c][d]=1;//如果上一次是另一个人,那么这一次就是这一个人
}
return f[a][b][c][d]=2;
}
int main(){
freopen("j5.in","r",stdin);
freopen("j5.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<=n;i++){
scanf("%d%d%d%d",&a,&b,&c,&d);
if (dfs(a,b,c,d)==2) puts("Roland");
else puts("Patrick");
}
return 0;
}
然后讲一下非正解的dp(比记搜慢)
#include <cstdio>
#include <algorithm>
using namespace std;
const int q[5][4]={{2,1,0,2},{1,1,1,1},{0,0,2,1},{0,3,0,0},{1,0,0,1}};
int n,a,b,c,d; bool f[61][61][61][61];//假设全是Roland赢
int main(){
for (int i=0;i<=60;i++)
for (int j=0;j<=60;j++)
for (int k=0;k<=60;k++)
for (int p=0;p<=60;p++)
for (int x=0;x<6-1;x++)
if (i-q[x][0]>=0&&j-q[x][1]>=0&&k-q[x][2]>=0&&p-q[x][3]>=0)
{
f[i][j][k][p]=1-f[i-q[x][0]][j-q[x][1]][k-q[x][2]][p-q[x][3]];//找到Patrick的方案
if (f[i][j][k][p]) break;//直接退出
}
freopen("j5.in","r",stdin);
freopen("j5.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<=n;i++){
scanf("%d%d%d%d",&a,&b,&c,&d);
if (!f[a][b][c][d]) puts("Roland");
else puts("Patrick");
}
return 0;
}