Loading

牛客小白月赛34 ACEF(待补)

链接:https://ac.nowcoder.com/acm/contest/11211/A
来源:牛客网

A.

题目描述

大科学家dddd最近在研究转基因白菜,白菜的基因序列由一串大写英文字母构成,dddd经过严谨的推理证明发现,只有当白菜的基因序列呈按位非递减形式时,这株白菜的高附加值将达到最高,于是优秀的dddd开始着手修改白菜的基因序列,dddd每次修改基因序列的任意位需要的代价是11,dddd想知道,修改白菜的基因序列使其高附加值达到最高,所需要的最小代价的是多少。

输入描述:

第一行一个正整数n(1≤n≤1000000)
第二行一个长度为n的字符串,表示所给白菜的基因序列
保证给出字符串中有且仅有大写英文字母

输出描述:

输出一行,表示最小代价

示例1

输入

复制

5
ACEBF

输出

复制

1

说明

改成ACEEF或者ACEFF,都只用改动一个字符,所需代价最小为1

懒得写了直接找了个最长不下降子序列的板子,求出来长度以后用n减一下即可。

//最长不下降子序列nlogn  Song 
 
#include<cstdio>
#include<algorithm>
#include <bits/stdc++.h>
using namespace std;
 
int a[1000005];
int d[1000005];
 
int main()
{
    int n;
    scanf("%d",&n);
    string s;
    cin >> s;
    for (int i=1;i<=n;i++) {
    	a[i] = s[i - 1] - 'A';
	}
    if (n==0)  //0个元素特判一下 
    {
        printf("0\n");
        return 0;
    }
    d[1]=a[1];  //初始化 
    int len=1;
    for (int i=2;i<=n;i++)
    {
        if (a[i]>=d[len]) d[++len]=a[i];  //如果可以接在len后面就接上 
        else  //否则就找一个最该替换的替换掉 
        {
            int j=upper_bound(d+1,d+len+1,a[i])-d;  //找到第一个大于它的d的下标 
            d[j]=a[i]; 
        }
    }
    printf("%d\n",n - len);    
    return 0;
}

链接:https://ac.nowcoder.com/acm/contest/11211/C
来源:牛客网

C.

题目描述

大科学家dddd最近在研究转基因白菜,白菜的基因序列由一串大写英文字母构成,dddd经过严谨的推理证明发现,只有当白菜的基因序列呈按位非递减形式时,这株白菜的高附加值将达到最高,于是优秀的dddd开始着手修改白菜的基因序列,dddd每次可以选择基因序列的一位进行修改,每次当她把一个字母xx修改成yy时,会产生∣x−y∣∣x−y∣(即xx与yy的ASCIIASCII码差值的绝对值)的改动偏移量,dddd希望,修改白菜的基因序列使其高附加值达到最高,并且基因序列的改动偏移量总和最小,她想知道最小的改动偏移量总和是多少。

输入描述:

第一行一个正整数n(1≤n≤1000000)
第二行一个长度为n的字符串,表示所给白菜的基因序列
保证给出字符串中有且仅有大写英文字母

输出描述:

输出一行,表示最小改动偏移量总和

示例1

输入

复制

5
AEEBC

输出

复制

5

说明

改成AEEEE或ACCCC偏移量总和最小
改成AEEEE,偏移量总和为|B-E|+|C-E|=3+2=5
改成ACCCC,偏移量总和为|E-C|+|E-C|+|B-C|=2+2+1=5
所以最小偏移量总和为5

直接暴力DP一下就完事了,转移方程见代码。

#include <bits/stdc++.h>
using namespace std;
int dp[1000005][26];//第i个数为A + j的最小总花费 
int n;
int main() {
	cin >> n;
	string s;
	cin >> s; 
	memset(dp, 0x3f3f3f3f, sizeof(dp));
	for(int i = 0; i < 26; i++) {
		dp[1][i] = abs(s[0] - 'A' - i);
	}
	for(int i = 2; i <= n; i++) {
		char c = s[i - 1];
		for(int j = 0; j < 26; j++) {
			for(int k = 0; k <= j; k++) {//单调不降的要求
				dp[i][j] = min(dp[i][j], dp[i - 1][j - k] + abs((c - 'A') - j));
			}
		}
	}
	int ans = 0x3f3f3f3f;
	for(int i = 0; i < 26; i++) {
		ans = min(ans, dp[n][i]);
	}
	cout << ans;
	return 0;
} 

E.

链接:https://ac.nowcoder.com/acm/contest/11211/E
来源:牛客网

题目描述

【题目描述】
读入一个n∗nn∗n的矩阵,对于一个矩阵有以下两种操作
11:顺时针旋180°180°
22:关于行镜像

[1234][13​24​]变成[3412][31​42​]给出qq个操作,输出操作完的矩阵

输入描述:

第一行一个数n(1≤n≤1000),表示矩阵大小
接下来n行,每行n个数,描述矩阵,其中数字范围为[1,2000]
一下来一行一个数q(1≤q≤100000),表示询问次数
接下来q行,每行一个数x(x=1或x=2),描述每次询问

输出描述:

n行,每行n个数,描述操作后的矩阵

示例1

输入

复制

2
1 2
3 4
1
1

输出

复制

4 3
2 1

示例2

输入

复制

2
1 2
3 4
1
2

输出

复制

3 4
1 2

易知顺时针旋转180度后\(a[i][j]->a[n - i + 1][n - j + 1]\),水平翻转后\(a[i][j]->a[n - i + 1][j]\),且这两个操作的性质与异或类似(操作两次不变)。又注意到第一个下标不管是哪种操作一定会变,第二个下标只有顺时针旋转会变,因此只需要统计这两种操作的奇偶性,然后最终的数组与原数组究竟是哪种对应关系即可。

#include <bits/stdc++.h>
using namespace std;
int o[1005][1005], a[1005][1005], n, q, cnt1 = 0, cnt2 = 0;
int main() {
	cin >> n;
	for(int i = 1; i <= n; i++) {
		for(int j = 1; j <= n; j++) {
			cin >> o[i][j];
		}
	}
	cin >> q;
	for(int i = 1; i <= q; i++) {
		int op;
		cin >> op;
		if(op == 1) cnt1++;
		else cnt2++;
	}
	for(int i = 1; i <= n; i++) {
		for(int j = 1; j <= n; j++) {
			if((cnt1 & 1) && (cnt2 & 1)) {
				a[i][j] = o[i][n - j + 1];
			} else if(cnt2 & 1) {
				 a[i][j] = o[n - i + 1][j];
			} else if(cnt1 & 1) {
				a[i][j] = o[n - i + 1][n - j + 1];
			} else {
				a[i][j] = a[i][j] = o[i][j];
			}
		}
	}
	for(int i = 1; i <= n; i++) {
		for(int j = 1; j <= n; j++) {
			cout << a[i][j] << " ";
		}
		cout << endl;
	}
}

F.

链接:https://ac.nowcoder.com/acm/contest/11211/F
来源:牛客网

题目描述

读入n,xn,x,给出nn个数a[1],a[2],……,a[n]a[1],a[2],……,a[n],求最小的区间[l,r][l,r],使a[l]+a[l+1]+……+a[r]≥xa[l]+a[l+1]+……+a[r]≥x,若存在相同长度区间,输出ll最小的那个

输入描述:

第一行两个数,n(1≤n≤10000000),x(1≤x≤10000)
第二行n个数a[i](1≤a[i]≤1000)

输出描述:

输出符合条件l,r(保证有解)

示例1

输入

复制

10 20
1 1 6 10 9 3 3 5 3 7

输出

复制

3 5

备注:

双指针+队列维护一段区间并维护一个值(区间和)。当区间和小于x则把r右移同时更新sum,若大于等于x则不断左移l并更新sum和最终答案,直到区间和小于x,然后再指针右移并更新sum。代码写丑了调了半天==

注意n很大,读入要用scanf。

#include <bits/stdc++.h>
#define int long long
using namespace std;
int n, x;
int l = 1, r = 0;
long long sum = 0;
queue<int> q;
int ans = 100000000, lmin = 100000000;
signed main() {
	cin >> n >> x;
	for(int i = 1; i <= n; i++) {
		int ai;
		scanf("%lld", &ai);
		if(sum < x) {
			sum += 1ll * ai;
			r++;
			q.push(ai);
		} else {
			while(sum >= 1ll * x && l <= r) {
				if(r - l + 1 < ans) {
					ans = r - l + 1;
					lmin = l;
				} else if(r - l + 1 == ans) {
					if(l < lmin) {
						lmin = l;
					}
				}
				l++;
				int now = q.front();
				q.pop();
				sum -= 1ll * now;
			}
			r++;
			sum += 1ll * ai;
			q.push(ai);
		}
	}
	while(sum >= 1ll * x && l <= r) {//为了判末尾
		if(r - l + 1 < ans) {
			ans = r - l + 1;
			lmin = l;
		} else if(r - l + 1 == ans) {
			if(l < lmin) {
				lmin = l;
			}
		}
		l++;
		int now = q.front();
		q.pop();
		sum -= 1ll * now;
	}
	if(n == 1) cout << 1 << " " << 1;
	else cout << lmin << " " << lmin + ans - 1;
	return 0;
}
//5 9
//1 1 1 1 9
//
//3 6
//2 4 6
posted @ 2021-05-28 23:51  脂环  阅读(201)  评论(0编辑  收藏  举报