启航组欢乐赛 题解

T1 买本子

这一道题我们可以考虑暴力分解:如果每一个包装所含本子的数量不能总共要买的本子数量整除的话,要买的包装总数要多一,然后求出各包装总共的钱数最后比大小即可。

#include<cstdio>
#include<cstring>
using namespace std;
int main(){
    int n, q, w, e, r, t, y, ans;
    scanf("%d %d%d %d%d %d%d",&n, &q, &r, &w, &t, &e, &y);
    if(n % q) q = (n / q) + 1;
    else q = n / q;
    
    if(n % w) w = (n / w) + 1;
    else w = n / w;
    
    if(n % e) e = (n / e) + 1;
    else e = n / e;
    
    q *= r;
    w *= t;
    e *= y;
    ans = q;
	if(ans > w) ans = w;
	if(ans > e) ans = e;
    printf("%d\n", ans);
    return 0;
}

T2 哥的八个猜想

专门开一个函数判断质数,然后按照 \(i\)\(j\) 都是质数的条件暴力枚举即可。

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
bool p(int num){
	for(int i = 2; i <= sqrt(num); i++)
		if(num % i == 0) return false;
	return true;
}
int main(){
	int n,i,j;
	cin >> n;
	for(i = 2; i <= n / 2; i++){
		j = n - i;
		if(p(i) && p(j)){
			cout << n << " = " << i << " + " << j << endl;
			break;
		}
	}return 0;
}

T3 成绩排名

开一个结构体冒泡排序即可,也可以写一个cmp函数用sort。

#include<stdio.h>
struct jxj {
	int yw;
	int sx;
	int yy;
	int sum;
	int id;
};
int main() {
	struct jxj a[500],temp;
	int i,j,n;
	scanf("%d",&n);
	for(i=1; i<=n; i++) {
		scanf("%d%d%d",&a[i].yw,&a[i].sx,&a[i].yy);
		a[i].sum=a[i].yw+a[i].sx+a[i].yy;
		a[i].id=i;
	}
	for(i=1; i<n; i++)
		for(j=1; j<=n-i; j++) {
			if(a[j].sum<a[j+1].sum) {
				temp=a[j];
				a[j]=a[j+1];
				a[j+1]=temp;
			} else if(a[j].sum==a[j+1].sum&&a[j].yw<a[j+1].yw) {
				temp=a[j];
				a[j]=a[j+1];
				a[j+1]=temp;
			} else if(a[j].sum==a[j+1].sum&&a[j].yw==a[j+1].yw&&a[j].id>a[j+1].id) {
				temp=a[j];
				a[j]=a[j+1];
				a[j+1]=temp;
			}
		}
	for(i=1; i<=5; i++)
		printf("%d %d\n",a[i].id,a[i].sum);
	return 0;
}

T4 蛇形矩阵

纯找规律题,简单的按照行数分类讨论一下即可。

#include<iostream>
#include<cstdio>
#include<iomanip>
#include<cstring>
using namespace std;
int main() {
	int n,i,j,k,t = 0;
	int a[21][21] = {0};
	cin >> n;
	for(k = 1; k <= n; k++){
		if(k % 2 == 0) {
            for(i = 1; i <= k; i++) {
				j = n - k + i;
				t++;
				a[i][j] = t;
				a[n + 1 - i][n + 1 - j] = n * n + 1 - t;
			}
        }else{ 
            for(i = k; i >= 1; i--) {
				j = n - k + i;
				t++;
				a[i][j] = t;
				a[n + 1 - i][n + 1 - j] = n * n + 1 - t;
			}
        }
	}
	for(i = 1; i <= n; i++) {
		for(j = 1; j <= n; j++)
			cout << setw(5) << a[i][j];
		cout << endl;
	}
	return 0;
}

T5 type

手写一个字符栈,写入就压栈,删除就弹栈。

#include<iostream>
#include<cstdio>
using namespace std;
int n,top;
char a[100001];
int main() {
	scanf("%d",&n);
	while(n--) {
		char ch[2];
		scanf("%s",ch);
		if(ch[0]=='T')cin>>a[++top];
		else if(ch[0]=='U') {
			int x;
			scanf("%d",&x);
			top-=x;
		} else {
			int x;
			scanf("%d",&x);
			cout<<a[x]<<endl;
		}
	}
	return 0;
}

T6 最优布线问题

最小生成树问题模板,直接跑一遍克鲁斯卡尔即可。

#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iomanip>
#include <iostream>

using namespace std;

int main() {
	int g[201][201];
	long long int minl[201];
	bool u[201];
	int n,i,j,k,tot;
	memset(g,0xffffff,sizeof(g));
	cin>>n;
	for (i = 1; i <= n; i++)
		for (j = 1; j <= n; j++)
			cin>>g[i][j];
	for (i = 2; i <= n; i++)
		minl[i] = 0x5ffffff;
	minl[1] = 0;
	minl[0] = 0x5ffffff;
	memset(u,true,sizeof(u));
	for (i = 1; i <= n; i++) {
		k = 0;
		for (j = 1; j <= n; j++)
			if ((u[j]) && (minl[j] < minl[k]))
				k = j;
		u[k] = false;
		for (j = 1; j <= n; j++)
			if ((u[j]) && (g[k][j] < minl[j]))
				minl[j] = g[k][j];
	}
	tot = 0;
	for (i = 1; i <= n; i++)
		tot += minl[i];
	printf("%d\n",tot);
	return 0;
}

T7 迷宫

直接跑一遍DFS就能得出答案。

#include<iostream>
#include<cstring>
using namespace std;
int n,s;
bool b[13][13];
const int dx[8]={0,0,1,1,1,-1,-1,-1},
          dy[8]={1,-1,1,0,-1,1,0,-1};

void go(int x,int y)
{
	if (x==1 && y==n){
		s++;
		return;
	}
	int i,xx,yy;
	for (i=0;i<=7;i++)
	{
		xx=x+dx[i];
		yy=y+dy[i];
		if (b[xx][yy])
		{
			b[xx][yy]=false;
			go(xx,yy);
			b[xx][yy]=true;
		}
	}
}
int main()
{
	int i,j,x;
	cin>>n;
	memset(b,0,sizeof(b));
	for (i=1;i<=n;i++)
	    for (j=1;j<=n;j++)
	    {
			cin>>x;
			b[i][j]=(x==0);
		}
	s=0;
	b[1][1]=false;
	go(1,1);
    cout<<s<<endl;
    return 0;
}


T8 S君的甜品店

Subtask 1:

直接暴力枚举即可,预计得分 20 分。

Subtask 2:

使用 \(O(n^3)\) 的算法枚举出从 \(i\)\(j\) 的每个区间(\(all_{i,j}\))然后用 \(dp_i=max(dp_i,dp_{j-1}+all_{j,i})\) 的状态转移方程求出最大值。

for(int i=1;i<=n;i++){
    for(int j=i;j<=n;j++){
        int f=1;
        for(int k=i;k<=j;k++)
            f=f*a[k]%19260817;
        all[i][j]=f;
    }
}
for(int i=1;i<=n;i++)
    for(int j=1;j<=i;j++)
        dp[i]=max(dp[i],dp[j-1]+all[j][i]);

预计得分50分。

Subtask 3:

我们可以发现一个性质,就是 \(all_{i,j}=all_{i,j-1}\times a_j\) ,即可以由前一个状态转移过来,我们就可以在 \(O(n^2)\) 的时间复杂度内预处理了。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=19260817;
ll a[10005],dp[10005],all[10005][10005];
int main() {
	int n,f=1;
	cin>>n;
	for(int i=1; i<=n; i++) cin>>a[i];
	for(int i=1; i<=n; i++) {
		all[i][i]=a[i]%mod;
		for(int j=i+1; j<=n; j++)
			all[i][j]=all[i][j-1]*a[j]%mod;
	}
	for(int i=1; i<=n; i++) 
		for(int j=1; j<=i; j++) 
			dp[i]=max(dp[i],dp[j-1]+all[j][i]);
	printf("%lld\n",dp[n]);
}

值得一提的是,如果你不开 long long 的话,预计和暴力老哥同分哦~

posted @ 2020-07-03 22:40  Inversentropir-36  阅读(141)  评论(0编辑  收藏  举报