1、[NOIP2017 普及组] 成绩
分析
签到题,略。
代码
#include<iostream>
#include<cstdio>
using namespace std;
int A,B,C;
int score(int,int,int);
void init();
void solve();
int main(){
init();
solve();
return 0;
}
int score(int a,int b,int c){
return 0.2*a+0.3*b+0.5*c;
}
void init(){
scanf("%d%d%d",&A,&B,&C);
}
void solve(){
printf("%d",score(A,B,C));
}
2、P3955 [NOIP2017 普及组] 图书管理员
分析
本题主要目的是将编号 i i i 的读者需求码 r e a d e r I d [ i ] readerId[i] readerId[i] 与从小到大排名后的图书编码 b o o k I d [ i ] bookId[i] bookId[i] 进行比较,遇到合适值直接输出并进入下一个编号中。
比较方式是取图书编码 b o o k I d [ i ] bookId[i] bookId[i] 最后 n u m [ i ] num[i] num[i] 个数字,即判断条件为 b o o k I d [ i ] % 1 0 n u m [ i ] = r e a d e r I d [ i ] bookId[i]\%10^{num[i]}=readerId[i] bookId[i]%10num[i]=readerId[i] 。
代码
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int MAXN=1e3;
int n,q;//书的数量、读者的数量
int bookId[MAXN+10],readerId[MAXN+10];
int num[MAXN+10];
void init();
void solve();
int main(){
init();
solve();
return 0;
}
void init(){
int i;
scanf("%d%d",&n,&q);
for(i=0;i<n;++i){
scanf("%d",bookId+i);
}
for(i=0;i<q;++i){
scanf("%d",num+i);
scanf("%d",readerId+i);
}
}
void solve(){
int i,j,t;
bool judge;
sort(bookId,bookId+n);
for(i=0;i<q;++i){
t=pow(10,num[i]);
judge=1;
for(j=0;j<n;++j){
if(bookId[j]%t==readerId[i]){
printf("%d\n",bookId[j]);
judge=0;
break;
}
}
if(judge){
printf("-1\n");
}
}
}
3、P3956 [NOIP2017 普及组] 棋盘
分析
类似迷宫图,主要使用记忆化 B F S BFS BFS 搜索。
令表示方式如下:
当前格 | 下一格 | |
---|---|---|
坐标 | ( x , y ) (x,y) (x,y) | ( t x , t y ) (tx,ty) (tx,ty) |
颜色 | c c c | t c tc tc |
最少金币 | s s s | t s ts ts |
当前格 ( x , y ) (x,y) (x,y) 和下一格 ( t x , t y ) (tx,ty) (tx,ty) 的颜色情况 ( c , t c ) (c,tc) (c,tc) :
if tc==-1: # 下个节点没有颜色
if table[x][y]==-1: # 已经施过魔法
continue
if s+2<ts: # 将下个节点变为同色
minValue[tx][ty]=s+2
q.push((node){tx,ty,c,s+2})
elif c==tc: # 下个节点和当前颜色相同
if s<ts:
minValue[tx][ty]=s
q.push((node){tx,ty,tc,s})
elif c!=tc: # 下个节点和当前颜色不同
if s+1<ts:
minValue[tx][ty]=s+1
q.push((node){tx,ty,tc,s+1})
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int MAXM=1e2;
const int MAXN=1e3;
struct node{
int x,y,c,s;//坐标 (x,y),颜色 c,需求金币数s
};
queue<node> q;
int ans=0x7f7f7f7f;//记录答案的最小值
int turn[4][2]={0,1,0,-1,1,0,-1,0};//控制方向
int table[MAXM+10][MAXM+10];//棋盘
int minValue[MAXM+10][MAXM+10];//棋盘中各点的最小值
int m,n;//棋盘大小,有颜色格子的数量
void init();
void solve();
int main(){
init();
solve();
return 0;
}
void init(){
int i,j,x,y,c;
scanf("%d%d",&m,&n);
memset(minValue,0x7f,sizeof(minValue));
memset(table,-1,sizeof(table));
// for(i=0;i<m;++i){
// for(j=0;j<m;++j){
// printf("%d\t",table[i][j]);
// }
// printf("\n");
// }
for(i=0;i<n;++i){
scanf("%d%d%d",&x,&y,&c);
table[x][y]=c;
}
}
void solve(){
int i,j;
int tx,ty,tc,ts;
//BFS
minValue[1][1]=0;
q.push((node){1,1,table[1][1],0});//压入起点
while(!q.empty()){
//获取当前节点信息
node tmp=q.front();q.pop();
int x=tmp.x,y=tmp.y,c=tmp.c,s=tmp.s;
//判断是否到终点
if(x==m&&y==m){
ans=min(ans,minValue[x][y]);
}
for(i=0;i<4;++i){
tx=x+turn[i][0],ty=y+turn[i][1];
if(tx>0&&ty>0&&tx<=m&&ty<=m){
tc=table[tx][ty],ts=minValue[tx][ty];
if(tc==-1){//下个节点没有颜色
if(table[x][y]==-1)//已经施过魔法
continue;
if(s+2<ts){//将下个节点变为同色
minValue[tx][ty]=s+2;
q.push((node){tx,ty,c,s+2});
}
}else if(c==tc){//下个节点和当前颜色相同
if(s<ts){
minValue[tx][ty]=s;
q.push((node){tx,ty,tc,s});
}
}else if(c!=tc){//下个节点和当前颜色不同
if(s+1<ts){
minValue[tx][ty]=s+1;
q.push((node){tx,ty,tc,s+1});
}
}
}
}
}
if(ans==0x7f7f7f7f){
printf("-1");
return;
}
printf("%d",ans);
}
4、P3957 [NOIP2017 普及组] 跳房子
分析
变量 | 定义 |
---|---|
n n n | 格子数量 |
d d d | 原弹跳距离 |
k k k | 希望的分数 |
x [ i ] x[i] x[i] | 格子 i i i 的坐标 |
s [ i ] s[i] s[i] | 格子 i i i 的分数 |
g g g | 消耗的金币 |
d p [ i ] dp[i] dp[i] | 格子i的最大分数 |
m i n d mind mind | 距离最小值 |
m a x d maxd maxd | 距离最大值 |
2、若花费 g g g 枚金币能得到 k k k 分,则花费 g + 1 g+1 g+1 枚金币依旧能够得到 k k k 分,因此答案 g ∈ [ 0 , x [ n ] ] g∈[\ 0,\ x[n]\ ] g∈[ 0, x[n] ],可用二分进行搜索。
3、可以通过动态规划来表示格子 i i i 的最大分数, d p [ i ] = m a x ( d p [ j ] + s [ i ] , d p [ i ] ) dp[i]=max(dp[j]+s[i],dp[i]) dp[i]=max(dp[j]+s[i],dp[i]) { j ∣ m i n d ≤ x [ i ] − x [ j ] ≤ m a x d } \{\ j\ |\ mind≤x[i]-x[j]≤maxd \ \} { j ∣ mind≤x[i]−x[j]≤maxd };可以简化为 d p [ i ] = m a x ( d p [ j ] ) + s dp[i]=max(dp[j])+s dp[i]=max(dp[j])+s
代码
1、二分 + d p +\ dp + dp( 50 50 50 分)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=5e5;
int g;//消耗的金币
int n;//格子数量
int d;//原弹跳距离
int k;//希望的分数
int x[MAXN+10];//格子 i 的坐标
int s[MAXN+10];//格子 i 的分数
int dp[MAXN+10];//格子 i 的最大分数
void init();
bool judge(int);
void solve();
int main(){
init();
solve();
return 0;
}
void init(){
int i;
scanf("%d%d%d",&n,&d,&k);
for(i=1;i<=n;++i){
scanf("%d%d",x+i,s+i);
}
}
bool judge(int mid){
memset(dp,-0x7f7f7f7f,sizeof(dp));
dp[0]=0;
int i,j;
int mind=max(d-mid,1);
int maxd=d+mid;
for(i=1;i<=n;++i){
for(j=0;j<i;++j){
if(x[i]-x[j]>=mind&&x[i]-x[j]<=maxd){
dp[i]=max(dp[j]+s[i],dp[i]);//dp
if(dp[i]>=k){
//mid右侧均满足最大分数 ≥k
return true;
}
}
}
}
return 0;//mid左侧均不满足最大分数 ≥k
}
void solve(){
int l=0,r=x[n];//g的可选范围
int mid;
//二分搜索
while(l!=r){
mid=(l+r)/2;
//判断答案在mid左侧(true)还是右侧(false)
if(judge(mid)){
r=mid;//左侧搜索
}else{
l=mid+1;//右侧搜索
}
}
if(judge(l)){
printf("%d",l);
}else{
//搜索完成后未找到g
printf("-1");
}
}
2、剪枝
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const int MAXN=5e5;
LL n;//格子数量
LL d;//原弹跳距离
LL k;//希望的分数
LL x[MAXN+10];//格子 i 的坐标
LL s[MAXN+10];//格子 i 的分数
LL dp[MAXN+10];//格子 i 的最大分数
void init();
bool judge(int);
void solve();
int main(){
init();
solve();
return 0;
}
void init(){
int i;
scanf("%lld%lld%lld",&n,&d,&k);
for(i=1;i<=n;++i){
scanf("%lld%lld",x+i,s+i);
}
}
bool judge(int mid){
memset(dp,-0x7f7f7f7f,sizeof(dp));
dp[0]=0;
int i,j;
LL mind=max(d-mid,1LL);
LL maxd=d+mid;
for(i=1;i<=n;++i){
for(j=i-1;j>=0;--j){
if(x[i]-x[j]>maxd)break;
if(x[i]-x[j]<mind)continue;
dp[i]=max(dp[j]+s[i],dp[i]);//dp
if(dp[i]>=k){
//mid右侧均满足最大分数 ≥k
return true;
}
}
}
return false;//mid左侧均不满足最大分数 ≥k
}
void solve(){
LL l=0,r=2010;//g的可选范围
LL mid;
//二分搜索
while(l!=r){
mid=(l+r)>>1;
//判断答案在mid左侧(true)还是右侧(false)
if(judge(mid)){
r=mid;//左侧搜索
}else{
l=mid+1;//右侧搜索
}
}
if(judge(l)){
printf("%lld",l);
}else{
//搜索完成后未找到g
printf("-1");
}
}