您的位置:首页 > 其它

2018.02.01【NOIP普及组】模拟赛D组

2018-02-01 16:45 417 查看

JZOJ NO.1 【2012.02.25普及组】牛车

这道题就是同车道前面有x头牛,车速降低D*X,低于最低限速不允许,一共可以有多少辆车

首先先讲一下我的方法O(n^2)

有m条车道,一条车道最多塞(n-1)/m+1头牛,所以贪心代码就出来了。

#include <cstdio>
#include <algorithm>
using namespace std;
int a[50001],s[50011],n,ans,m,d,l;
int main(){
scanf("%d%d%d%d",&n,&m,&d,&l);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
sort(a+1,a+1+n);//快排
for (int i=1;i<=n;i++){
if (a[i]<l) continue; int j;//本来就不能走何必贪心
for (j=1;j<=(n-1)/m+1;j++)
if (s[j]<m&&a[i]-d*(j-1)>=l) {s[j]++;break;}//加入第j行
if (j<=(n-1)/m+1) ans++; //说明塞进去了
}
printf("%d",ans);
return 0;
}


但是这种方法并不是最优解。最优解是这样的。O(n)

#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: