NOIP2017普及组试题题解
1.成绩
原题:https://www.luogu.com.cn/problem/P3954
代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int a,b,c;
int main(){
cin>>a>>b>>c;
cout<<a/10*2+b/10*3+c/10*5;
return 0;
}
解题思路:
因为数据保证a,b,c都是10的整倍数,所以直接做加法就行了
2.图书管理员
代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e3+255,w[39]={1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000};
int n,q,p[N];
int main(){
cin>>n>>q;
for(int i=1;i<=n;i++)cin>>p[i];
sort(p+1,p+n+1);
for(int i=1,x,b;i<=q;i++){
bool flag=0;
cin>>x>>b;
for(int j=1;j<=n;j++){
if(p[j]%w[x]==b){
cout<<p[j]<<'\n';
flag=1;
break;
}
}
if(!flag)cout<<-1<<'\n';
}
return 0;
}
解题思路:
列举出10的次幂,每次去模10的次幂,判断是否相同即可
3.棋盘
代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e3+255,dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
int a[N][N],m,n,ans=1e9,dp[N][N];
void dfs(int x,int y,int precolor,int sum){
if(x==m&&y==m){
if(ans>sum)ans=sum;
return;
}
if(sum>=dp[x][y])return;
else dp[x][y]=sum;
for(int i=0;i<4;i++){
int xx=x+dx[i],yy=y+dy[i];
if(xx<1||xx>m||yy<1||yy>m)continue;
if(a[xx][yy]==precolor){
dfs(xx,yy,precolor,sum);
continue;
}else if(!a[xx][yy]&&precolor==a[x][y]){
dfs(xx,yy,precolor,sum+2);
}else if(a[xx][yy]){
dfs(xx,yy,a[xx][yy],sum+1);
}
}
}
int main(){
memset(a,0,sizeof(a));
memset(dp,1,sizeof(dp));
cin>>m>>n;
for(int i=1;i<=n;i++){
int x,y,z;
cin>>x>>y>>z;
a[x][y]=z+1;
}
dfs(1,1,a[1][1],0);
if(ans!=1e9)cout<<ans;
else cout<<"-1";
return 0;
}
解题思路:
记录每个格子的颜色,进行深搜,分三种情况:第一种,下一个格子的颜色与precolor相等,直接dfs;第二种,下一个格子无色,且当前格子与precolor颜色相等,金币数+2;第三种,下一个格子有色,但和当前格子颜色不同,金币数+1。再加上最优性剪枝,这道题就可以AC了
4.跳房子
代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 5e5+255;
ll n,d,k,x[N],s[N],sum=0,dp[N],maxdis,jid;
bool dpp(ll fir,ll sec){
memset(dp,200,sizeof(dp));
deque<int>q;
dp[0]=0;int fp=0;
for(int i=1;i<=n;i++){
while(fp<i&&x[i]-x[fp]>=fir){
while(q.size()&&dp[q.back()]<=dp[fp])q.pop_back();
q.push_back(fp);
fp++;
}
while(q.size()&&x[i]-x[q.front()]>sec)q.pop_front();
if(q.size())dp[i]=max(dp[i],dp[q.front()]+s[i]);
if(dp[i]>=k)return 1;
}
return 0;
}
int main(){
cin>>n>>d>>k;
for(int i=1;i<=n;i++){
cin>>x[i]>>s[i];
sum+=(s[i]>0?s[i]:0);
if(s[i]>0){
maxdis=max(maxdis,x[i]-x[jid]);
jid=i;
}
}
if(sum<k){
cout<<-1;
return 0;
}else{
int l=-1,r=maxdis;
while(l+1<r){
int mid=(l+r)/2;
if(dpp(max(1ll,d-mid),d+mid))r=mid;
else l=mid;
}
cout<<r;
}
return 0;
}
解题思路:
求出每个距离中最大的差值,进行二分。在判断是否可行时,使用了双端队列来优化,这样可以排除不用的数据,使复杂度大大降低
注意事项:
1.在初始化dp时,要初始化为一个最小值,并把dp[0]初始化为0

浙公网安备 33010602011771号