2021曲阜师范大学校赛题解

密码: qfnuacm

A

题意好像没什么要解释的,照着来就行

// Problem: 积分赛
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/14450/A
// Memory Limit: 524288 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define ll long long
#define re return

using namespace std;

typedef pair<int, int> PII;

int dx[4] = {-1,0,1,0};
int dy[4] = {0,1,0,-1};

int n;

int main(){
	int a, b, c, d;
	cin >> n;
	int maxx = -1;
	int id = 1;
	for(int i = 1; i <= n; i++){
		cin >> a >> b >> c >> d;
		int summ = b * 1 + c * 2 + d * 3;
		if(summ > maxx){
			id = a;
			maxx = summ;
		}
		
	}
	cout << id << " " << maxx;
	re 0;
}

B

就是求一个极差求一个方差(全是根据题意来的)

// Problem: 数据处理
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/14450/B
// Memory Limit: 524288 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define ll long long
#define re return

using namespace std;

typedef pair<int, int> PII;

int dx[4] = {-1,0,1,0};
int dy[4] = {0,1,0,-1};

int T;
int n;
int a[1000 + 10];

int main(){
	cin >> T;
	while(T--){
		cin >> n;
		int maxx = -1;
		int minn = 99999999;
		int summ = 0;
		for(int i = 1; i <= n; i++){
			scanf("%d",a + i);
			summ += a[i];
			maxx = max(maxx, a[i]);
			minn = min(minn, a[i]);
		}
		
		double avg = summ * 1.0 / n;
		double ans = 0.0;
		
		for(int i = 1; i <= n; i++){
			ans += ((a[i] - avg) * (a[i] - avg));
		}
		
		printf("%d %.3lf\n", (maxx - minn), ans / n);
	}
	re 0;
}

C

裸的容斥原理

加上覆盖的减去重复算过的即可

// Problem: 涂色
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/14450/C
// Memory Limit: 524288 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define ll long long
#define re return

using namespace std;

typedef pair<int, int> PII;

int dx[4] = {-1,0,1,0};
int dy[4] = {0,1,0,-1};

int T;

ll n, m, r, c;

int main(){
	cin >> T;
	while(T--){
		cin >> n >> m >> r >> c;
		ll summ = n * m;
		cout << summ - r * m - c * n + r * c << endl;
	}
	re 0;
}

D

这题是思维题了

按从小到大排序

如果前四个数的和比最多的那个还少,那么一定可以用最后一个的水果数来匹配前面的所有水果

如果前四个的和大于第五个,那我们就先让前四个内部匹配使剩下的刚好等于第五个。这个时候就回到了前四个小于等于第五个的问题,这样做显然答案是ssum/2。

证明:假设我们不能让前四个内部匹配, 使其剩下的和小于等于第五个,那么说明我们完成前四个的匹配操作之后,只剩下了一种水果。因为只有这样才会导致不能继续匹配。而根据我们的假设, 剩下的这种水果的数量是比第五个要大的,与我们最开始的规定第五个最大不符。所以不可能出现这种情况。

所以如果前四个的和比第五个要大, 那么它至少会还剩下两种水果。这两种还能继续匹配然后匹配下去一定可以使最后的结果是前四个的和小于等于第五个, 我们就让他等于第五个好了(奇数的话就多一个, 无所谓)

例如:1 2 3 4 6

用前面的往后面的去配对,最后会

// Problem: 水果盒
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/14450/D
// Memory Limit: 524288 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define ll long long
#define re return

using namespace std;

typedef pair<int, int> PII;

int dx[4] = {-1,0,1,0};
int dy[4] = {0,1,0,-1};

ll a[10];

int main(){
	ll summ = 0;
	for(int i = 1; i <= 5; i++){
		cin >> a[i];
		summ += a[i];
	}
	
	sort(a + 1, a + 1 + 5);
	
	ll cnt = 0;
	
	for(int i = 1; i <= 4; i++){
		cnt += a[i];
	}
	
	if(cnt < a[5]){
		cout << cnt;
	}
	else cout << summ / 2;
    re 0;
}

F

按照题意模拟即可

注意一下雨天的情况

// Problem: 运动会
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/14450/F
// Memory Limit: 524288 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define ll long long
#define re return

using namespace std;

typedef pair<int, int> PII;

int dx[4] = {-1,0,1,0};
int dy[4] = {0,1,0,-1};

int main(){
	int n, a;
	cin >> n >> a;
	double summ = 1.0 * a;
	double before = 1.0 * a;
	string s;
	cin >> s;
	for(int i = 1; i < s.size(); i++){ // 因为第一天不管什么样都得跑,所以直接从第二天开始
		if(s[i] == 's'){
			summ += (before * 1.3);
			before *= 1.3;
		}
		else if(s[i] == 'c'){
			summ += (before * 0.8);
			before *= 0.8;
		}
		else{
			if(s[i + 1] != 'r') before = 1.0 * a;
		}
	}
	printf("%.3lf", summ);
	re 0;
}

G

观察之后我们发现,

首先,某两个数相同就一定可以成功,这是显然的

根据这个性质,我们只需要让某两个数相等即可

对于这两个数,有两种操作,一个同时是-1,对他们相等一定是没有贡献的;一个是+2一个-1,本质上是让这两个数的差减少3,这对答案是有贡献的

所以说任意两个数的差值是3的倍数是可以完成操作的

不过这时候有一点要考虑的,就是你减一的同时,另一个数的大小能不能支撑你完成这些操作

这是一定的,因为即使一个数减到头了,你们我们可以通过减其他的两个数来对其进行+2的操作,这样就能增加了轮数

// Problem: 一个简单的思维题
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/14450/G
// Memory Limit: 524288 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define ll long long
#define re return

using namespace std;

typedef pair<int, int> PII;

int dx[4] = {-1,0,1,0};
int dy[4] = {0,1,0,-1};

int T;

int main(){
	cin >> T;
	int a[5];
	while(T--){ 
		cin >> a[1] >> a[2] >> a[3];

		if(a[1] == a[2] || a[2] == a[3] || a[1] == a[3]){
			cout << "Yes" << endl;
			continue;
		} 
		
		if(abs(a[1] - a[2]) % 3 == 0 || abs(a[1] - a[3]) % 3 == 0 || abs(a[2] - a[3]) % 3 == 0) cout << "Yes" << endl;
		else cout << "No" << endl;
	}
	re 0;
}

H

首先他问我们某一段的和是不是一个t的倍数(题目中是n),那么一段和我们很自然的就联想到前缀和了。而且我们知道,如果对每一个前缀和都进行%t处理,那么就一定会使得某些数是0(假设这个数的位置是i),那么就说明从1到i的所有的数的和都是t的倍数。那么我们也会得到有的和并不是0,而是1~(t - 1)中的数。但是不妨碍里面有相同的数。

假设 s[i] % t = x,那么我们有取余的定义可知:
s [ i ] / t = n ⋯ x 即 t ∗ n + x = s [ i ] s[i] / t = n \cdots x \\ 即t * n + x = s[i] s[i]/t=nxtn+x=s[i]
那么假设还有一个数s[j]的取余结果也是x,同理
t ∗ m + x = s [ j ] t * m + x = s[j] tm+x=s[j]
两式相减得:
t ∗ n − t ∗ m = s [ i ] − s [ j ] t ∗ ( n − m ) = s [ i ] − s [ j ] t*n - t*m=s[i]-s[j]\\ t*(n-m) = s[i]-s[j] tntm=s[i]s[j]t(nm)=s[i]s[j]
那么就可以得到:
( s [ i ] − s [ j ] ) / t = ( n − m ) ⋯ 0 (s[i]-s[j]) / t = (n - m) \cdots 0 (s[i]s[j])/t=(nm)0
即:
( s [ i ] − s [ j ] ) % t = 0 (s[i]-s[j]) \% t = 0 (s[i]s[j])%t=0
那么我们就能得到一下结论:

如果某个余数在出现过之后在它后面再次出现过,那么 [ i , j ]这个区间的和就可以是t的倍数。

所以t就是j - i了

然后遍历一遍取最大值就好了

但是我们要反过来考虑,一个区间能不能被这个t所整除,只需要记录最后一次这个余数出现的位置即可,这样就可以保证每一次的长度尽可能的大

如果得到的前缀和数组取模完之后答案为0代表什么?自然就意味着前面所有的数都是它的倍数,那么此时的长度就是i,这就是为什么许多同学190的原因。

// Problem: "Inference"
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/14450/H
// Memory Limit: 524288 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define ll long long
#define re return

using namespace std;

typedef pair<int, int> PII;

int dx[4] = {-1,0,1,0};
int dy[4] = {0,1,0,-1};

int n;
int a[1000000 + 10];
int s[1000000 + 10];
int pre[1000000 + 10]; // 存储最后一次出现的位置

int main(){
	cin >> n;
	for(int i = 1; i <= n; i++){
		scanf("%d", a + i);
		
		s[i] = (s[i - 1] + a[i] % n) % n;
		pre[s[i]] = i;
	}
	
	int t = -1;
	
	for(int i = 1; i <= n; i++){
		if(s[i] == 0){
			t = max(t, i);
		}
		else t = max(t, pre[s[i]] - i);
	}
	cout << t;
	re 0;
}

I

中号模拟

根据题意来做就好了

// Problem: 寻找字符串
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/14450/I
// Memory Limit: 524288 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define ll long long
#define re return
#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;

int dx[4] = {-1,0,1,0};
int dy[4] = {0,1,0,-1};

int n, m, q;
string s;
char mapp[110][110];

struct node{
	vector<PII> id;
}p[128]; // 记录每次每个字母出现的位置,方便后续查找

bool find(string s){
	int l = p[(int)s[0]].id.size();
    int len = s.size(); //字符串的长度
    for (int i = 0; i < l; i++){
        // 看八个方向有没有

        int x = p[(int)s[0]].id[i].x;
        int y = p[(int)s[0]].id[i].y;

        int num = 0; // 现在s的第几个字符
        int xx = x;
        int yy = y;

        // up
        while(yy < n){
            if(mapp[xx][++yy] == s[++num]){
                continue;
            }
            else break;
        }
        if(num == len)
            return 1;
        
        //down

        num = 0;
        xx = x;
        yy = y;
        while(yy >= 0){
            if(mapp[xx][--yy] == s[++num]){
                continue;
            }
            else break;
        }
        if(num == len)
            return 1;

        //left
        num = 0;
        xx = x;
        yy = y;
        while(xx >= 0){
            if(mapp[--xx][yy] == s[++num]){
                continue;
            }
            else break;
        }
        if(num == len)
            return 1;

        // right
        num = 0;
        xx = x;
        yy = y;
        while(xx < m){
            if(mapp[++xx][yy] == s[++num]){
                continue;
            }
            else break;
        }
        if(num == len)
            return 1;

        // left + up
        num = 0;
        xx = x;
        yy = y;
        while(xx >= 0 && yy < n){
            if(mapp[--xx][++yy] == s[++num]){
                continue;
            }
            else break;
        }
        if(num == len)
            return 1;

        //left + down
        num = 0;
        xx = x;
        yy = y;
        while(xx >= 0 && yy >= 0){
            if(mapp[--xx][--yy] == s[++num]){
                continue;
            }
            else break;
        }
        if(num == len)
            return 1;
        
        //right + up
        num = 0;
        xx = x;
        yy = y;
        while(xx < m && yy < n){
            if(mapp[++xx][++yy] == s[++num]){
                continue;
            }
            else break;
        }
        if(num == len)
            return 1;
        
        //right + down
        num = 0;
        xx = x;
        yy = y;
        while(xx < m && yy >= 0){
            if(mapp[++xx][--yy] == s[++num]){
                continue;
            }
            else break;
        }
        if(num == len)
            return 1;
    }
    return 0;
}

int main(){
	cin >> m >> n;
	for(int i = 0; i < m; i++){
		scanf("%s",mapp[i]);
		for(int j = 0; j < n; j++){
            p[(int)mapp[i][j]].id.push_back({i, j});
        }
	}
	
	cin >> q;
	while(q--){
		cin >> s;
		if(find(s)) cout << "YES" << endl;
		else cout << "NO" << endl;
	}
	re 0;
}

后面的三个为官方题解

J

2021曲阜师范大学校赛题解_第1张图片

你可能感兴趣的:(题目笔记)