NOIP2014普及组试题题解

发布时间 2023-05-24 21:16:04作者: 天雷小兔

1.珠心算测验

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 2e4+39+7;
int mp[N],n,a[N],ans=0;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i];
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(a[i]!=a[j]){
				mp[a[i]+a[j]]=1;
			}
		}
	}
	for(int i=1;i<=n;i++){
		if(mp[a[i]]){
			ans++;
		}
	}
	cout<<ans;
	return 0;
}

  

解题思路:

用一个哈希表统计和即可

 

2.比例简化

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int gcd(int a,int b){
	if(!b)return a;
	return gcd(b,a%b);
}
int a,b,l,ans1,ans2;
int main(){
	cin>>a>>b>>l;
	ans1=l;
	ans2=1;
	for(int i=1;i<=l;i++){
		for(int j=1;j<=l;j++){
			if(gcd(i,j)==1){
				if(i*b>=a*j&&ans1*j>=ans2*i){
					ans1=i;
					ans2=j;
				}
			}
		}
	}
	cout<<ans1<<' '<<ans2;
	return 0;
}

  

解题思路:

判断i,j是否互质,且比值大于等于a/b即可

注意事项:

1.由于c++中实数操作可能会丢失精度,所以要把a/b>c/d换成a*d>b*c

 

3.螺旋矩阵

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,x,y;
int dfs(int n,int x,int y){
	if(x==1)return y;
	if(y==n)return n+x-1;
	if(y==1)return 4*n-2-x;
	if(x==n)return 3*n-y-1;
	return dfs(n-2,x-1,y-1)+4*(n-1);
}
int main(){
	cin>>n>>x>>y;
	cout<<dfs(n,x,y);
	return 0;
}

  

解题思路:

由矩阵可以看出,分5种情况:第一种,x=1,直接返回y

                                                 第二种,x=n,可以找到规律,是3n-y-1

                                                 第三种,y=1,可以找到规律,是4n-x-2

                                                 第四种,y=n,可以找到规律,是n+x-1

                                              第五种,在中心,返回dfs(n-2,x-1,y-1)+4(n+1),向内递进一层

最终可以得出答案

 

4.子矩阵

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 39+7;
int n,m,r,c,a[N],num[N][N],sol=1e9,w[N],g[N][N],dp[N][N];
void init(){
	for(int i=1;i<=m;i++){
		w[i]=0;
		for(int j=1;j<r;j++)w[i]+=abs(num[a[j]][i]-num[a[j+1]][i]);
	}
	for(int i=1;i<=m;i++){
		for(int j=i+1;j<=m;j++){
			g[i][j]=0;
			for(int k=1;k<=r;k++){
				g[i][j]+=abs(num[a[k]][i]-num[a[k]][j]);
			}
		}
	}
}
int dpp(){
	memset(dp,0x7f,sizeof(dp));
	dp[0][0]=0;
	for(int k=1;k<=c;k++){
		for(int i=k;i<=m;i++){
			for(int j=k-1;j<i;j++){
				dp[i][k]=min(dp[i][k],dp[j][k-1]+w[i]+g[j][i]);
			}
		}
	}
	int ans=dp[c][c];
	for(int i=c+1;i<=m;i++)ans=min(ans,dp[i][c]);
	return ans;
}
void dfs(int tr){
	if(tr>r){
		
		init();
		sol=min(sol,dpp());
		return;
	}
	for(int i=a[tr-1]+1;i<=n;i++){
		a[tr]=i;
		dfs(tr+1);
	}
}
int main(){
	cin>>n>>m>>r>>c;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cin>>num[i][j];
		}
	}
	dfs(1);
	cout<<sol;
	return 0;
}

  

解题思路:

暴力枚举行的组合是C(n,r),在使用dp去计算列的最小值,每次取最小值即可,时间复杂度是O(C(n,r)*m3)