NOIP2018普及组试题题解

1.标题统计

原题:https://www.luogu.com.cn/problem/P5015

#include<bits/stdc++.h>
#define ll long long
using namespace std;
string s;int ans=0;
int main(){
	getline(cin,s);int len=s.length();
	for(int i=0;i<len;i++){
		if(s[i]>='0'&&s[i]<='9')ans++;
		else if(s[i]>='a'&&s[i]<='z')ans++;
		else if(s[i]>='A'&&s[i]<='Z')ans++;
	}
	cout<<ans;
	return 0;
}

  

解题思路:

getline读入字符串,遍历字符串,统计字符个数

 

2.龙虎斗

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5+255;
ll n,m,sol,sum1=0,sum2=0,ans=1e18,c[N],p1,s1,p2,s2;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++)cin>>c[i];
	cin>>m>>p1>>s1>>s2;
	p2=m;
	c[p1]+=s1;
	for(int i=1;i<=n;i++){
		if(i==m)continue;
		else if(i<m)sum1+=(m-i)*c[i];
		else if(i>m)sum2+=(i-m)*c[i];
	}sol=abs(sum2-sum1);
	if(sum1<sum2){
		for(int i=1;i<m;i++){
			ll sum3=sum1+(m-i)*s2;
			if(abs(sum2-sum3)<sol){
				sol=abs(sum2-sum3);
				p2=i;
			}else if(abs(sum2-sum3)==sol&&p2>i)p2=i;
		}
	}else if(sum2<sum1){
		for(int i=m+1;i<=n;i++){
			ll sum3=sum2+(i-m)*s2;
			if(abs(sum1-sum3)<sol){
				sol=abs(sum1-sum3);
				p2=i;
			}else if(abs(sum1-sum3)==sol&&p2>i)p2=i;
		}
	}
	cout<<p2;
	return 0;
}

  

解题思路:

判断p1的位置,遍历整个棋盘,枚举差值,取最小差值的编号就是答案

 

3.摆渡车

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 4e6+255;
ll n,m,a[N],b[N],f[N],mt;
int main(){
	cin>>n>>m;
	ll t;
	for(ll i=1;i<=n;i++){
		cin>>t;
		mt=max(mt,t);
		a[t]++;
		b[t]+=t;
	} 
	for(ll i=1;i<mt+m;i++){
		a[i]+=a[i-1];
		b[i]+=b[i-1];
	}
	for(ll i=0;i<mt+m;i++)f[i]=a[i]*i-b[i];
	for(ll i=0;i<mt+m;i++){
		if((i>=m)&&(a[i]==a[i-m])){
			f[i]=f[i-m];
			continue;
		}
		ll j=max(i-2*m,0ll);
		for(;j<=i-m;j++){
			f[i]=min(f[i],f[j]+(a[i]-a[j])*i-(b[i]-b[j]));
		}
	}
	ll ans=f[mt];
	for(ll i=mt+1;i<mt+m;i++)ans=min(ans,f[i]);
	cout<<ans;
	return 0;
}

  

解题思路:

使用dp求解最短等待时间,状态转移方程是f(i)=min(f(j)+sum(a[k]*k-b[k]))(j<k<=i),使用前缀和,滑动窗口,剪枝优化可以大大降低复杂度

 

4.对称二叉树

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e6+255;
int ans=0;
struct node{
	int l,r,v;
}tree[N*4];
bool dfs(int l,int r){
	if(tree[l].v!=tree[r].v)return 0;
	if(l==-1&&r==-1)return 1;
	else if(l==-1)return 0;
	else if(r==-1)return 0;
	return dfs(tree[l].r,tree[r].l)&&dfs(tree[l].l,tree[r].r);
}
int count(int root){
	if(tree[root].l==-1&&tree[root].r==-1)return 1;
	if(tree[root].l==-1)return count(tree[root].r)+1;
	if(tree[root].r==-1)return count(tree[root].l)+1;
	return count(tree[root].l)+count(tree[root].r)+1;
}
int main(){
	int n;cin>>n;
	for(int i=1;i<=n;i++)cin>>tree[i].v;
	for(int i=1;i<=n;i++)cin>>tree[i].l>>tree[i].r;
	for(int i=1;i<=n;i++){
		if(dfs(i,i)){
			ans=max(ans,count(i));
		}
	}
	cout<<ans;
	return 0;
}

  

解题思路:

建立两个指针,遍历子树,判断是否对称,如果对称,求最大节点数即可

posted @ 2023-05-21 15:08  天雷小兔  阅读(44)  评论(0)    收藏  举报