(6/6) Codeforces Round #455 (Div. 2)

(6/6) Codeforces Round #455 (Div. 2)

A. Generate Login

题意:

给你两个字符串a,b要求取a的任意前缀和b的任意前缀结合,要求最后得到的字符串字典序最小。

思路:

首先a的第一个字符一定要取,接下来从a的第二个字符和b的首字符开始,比较a的每一位和b的每一位,如果a的字符小放a再循环比较;否则放b,退出循环。如果a全部放进去了,那么接下来放b的第一个字符。

代码:

#include <bits/stdc++.h>
#define int long long
using namespace std;

void work() {
	string a, b;
	cin >> a >> b;
	string res;
	res += a[0];
	int sza = a.size(), szb = b.size();
	int f = 0;
	// cout << res << endl;
	for (int i = 1, j = 0; i < sza;) {
		if (a[i] < b[j]) {
			res += a[i];
			i++;
		} else {
			res += b[j];
			f = 1;
			break;
		}
	}
	if (f) cout << res << endl;
	else {
		res += b[0];
		cout << res << endl;
	}
}

int32_t main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int cas;
	cas = 1;
	while (cas--) work();
}

B. Segments

题意:

给你一个数n,在x轴上从0到n一共n+1个点。

从n+1个点任取两个就可以组成线段。问需要多少个x轴才能把所有线段覆盖。

如:n为4需要6个x轴。

思路:

n+1个点把x轴分为n个边,枚举任意两个点,对对应的边加上权值1,答案为权值最大的边。

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
int v[1000];


void work() {
	int n;
	cin >> n;
	for (int i = 0; i <= n; i++) {
		for (int j = i + 1; j <= n; j++) {
			for (int k = i; k < j; k++) v[k + 1]++;
		}
	}
	int ans = 0;
	for (int i = 1; i <= n; i++) ans = max(ans, v[i]);
	cout << ans << endl;
}

int32_t main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int cas = 1;
	while (cas--) work();
}

C. Python Indentation

题意:

给你一串字符包含s和f,f代表for循环,s代表语句。

在python中用缩进代表代码块,问此字符串一共可以组成多少种代码。

思路:

f [ i , j ] f[i, j] f[i,j]代表第 i i i个语句缩进为 j j j。那么第 n n n位最多缩进 n − 1 n-1 n1,所以答案为 ∑ ( f [ n , 0 ] , f [ n , 1 ] . . . f [ i , n − 1 ] ) \sum(f[n,0], f[n, 1]...f[i,n-1]) (f[n,0],f[n,1]...f[i,n1])

那么如果当前位为 f f f,那么下一位一定缩进。 f [ i + 1 , j + 1 ] = f [ i , j ] f[i+1, j+1]=f[i,j] f[i+1,j+1]=f[i,j]。如果当前位为 s s s,那么下一位最多等于上一位的缩进,最小不缩进。所以对于下一位的缩进 k k k f [ i + 1 , k ] = ∑ ( f [ i + 1 , k ] , f [ i + 1 , k + 1 ] . . . f [ i , n − 1 ] ) f[i+1, k]=\sum(f[i+1,k], f[i+1,k+1]...f[i,n-1]) f[i+1,k]=(f[i+1,k],f[i+1,k+1]...f[i,n1])

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
constexpr int mod = 1e9 + 7;
int f[5010][5010];
int a[5010];

void work() {
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++) {
		string x;
		cin >> x;
		if (x[0] == 's') a[i] = 1;
		else a[i] = 0;
	}
	
	f[1][0] = 1;
	for (int i = 1; i <= n; i++) {
		if (a[i] == 0) {
			for (int j = 0; j <= n - 1; j++)
				(f[i + 1][j + 1] = f[i][j]) %= mod;
		} else {
			int sum = 0;
			for (int j = n - 1; j >= 0; j--) {
				(sum += f[i][j]) %= mod;
				f[i + 1][j] = sum;
			}
		}
	}
	int ans = 0;
	for (int i = 0; i <= n - 1; i++) (ans += f[n][i]) %= mod;
	cout << (ans % mod + mod) % mod << endl;
}

int32_t main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	
	int cas;
	cas = 1;
	while (cas--) work();
}

D. Colorful Points

题意:

给你一个字符串仅包含 a a a z z z中的任意个字符,对于每次操作,对于每个字符,如果两侧存在至少一个字符与当前字符不同,则此字符可以删除。问最少进行多少次操作才不能操作。

思路:

暴力模拟,把相邻的且相同的字符归为一类放在新开辟的数组中,当数组中的元素小于等于1时,操作停止。

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
using pii = pair<int, int>;

void work() {
	string s;
	cin >> s;
	vector<pii> v;
	for (int i = 0; i < (int)s.size(); i++) {		
		if (i == 0) {
			v.push_back({s[i] - 'a', 1});
			continue;
		} 
		if (s[i] == s[i - 1]) v[(int)v.size() - 1].second++;
		else v.push_back({s[i] - 'a', 1});
	}
	// cout << v.size() <<endl;
	
	int res = 0;
	while (1) {
		if (v.size() == 1 || v.size() == 0) break;
		res++;
		for (int i = 0; i < v.size(); i++) 
			if (i == 0 || i == v.size() - 1) v[i].second--;
			else v[i].second -= 2;
		
		vector<pii> t;
		
		for (int i = 0; i < v.size(); i++) {
			if (v[i].second <= 0) continue;
			t.push_back(v[i]);
			int j = i + 1;
			while (j < v.size() && (v[j].first == v[i].first || v[j].second <= 0)) {
				
				if (v[j].second > 0) t[t.size() - 1].second += v[j].second;
				j++;
			}
			i = --j;
		}
		v = t;
	}
	cout << res << endl;
}

int32_t main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int cas;
	cas = 1;
	while (cas--) work();
}

E. Coprocessor

题意:

给你一个有向图,n个节点,每个节点有权值1或者0,按照拓扑排序删点,如果遇到连续的删1操作(可以为1次),则需要动用机器,问最少用多少次机器。

思路:

贪心,先全删0,删到不能再删,再删1;再全删0,删到不能再删,再删1…如此往复,求得操作次数。

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
constexpr int maxn = 100010;
vector<int> g[maxn];
int d[maxn];
int a[maxn];

void work() {
	int n, m;
	cin >> n >> m;
	for (int i = 1; i <= n; i++) cin >> a[i];
	for (int i = 1; i <= m; i++) {
		int a, b;
		cin >> a >> b;
		a++, b++;
		g[b].push_back(a);
		d[a]++;
	}
	queue<int> q[2];
	int res = 0, cnt = 0;
	for (int i = 1; i <= n; i++) if (d[i] == 0) q[a[i]].push(i);
	while (cnt != n) {	
		if (q[0].size()) {
			while (q[0].size()) {
				int t = q[0].front();
				q[0].pop();
				cnt++;
				for (int i = 0; i < (int)g[t].size(); i++) {
					int v = g[t][i];
					d[v]--;
					if (d[v] != 0) continue;
					q[a[v]].push(v);
				}
			}
		} else {
			res++;
			while (q[1].size()) {
				int t = q[1].front();
				q[1].pop();
				cnt++;
				for (int i = 0; i < (int)g[t].size(); i++) {
					int v = g[t][i];
					d[v]--;
					if (d[v] != 0) continue;
					q[a[v]].push(v);
				}
			}
		}
	}
	cout << res << endl;
}

int32_t main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int cas;
	cas = 1;
	while (cas--) work();
}

F. AND-permutations

题意:

给一个 n n n,构造两个n的全排列,第一个序列 p i ≠ i pi≠i pi=i p i pi pi & i = 0 i=0 i=0,第二个序列 p i ≠ i pi≠i pi=i p i pi pi & i ≠ 0 i≠0 i=0

p i pi pi 1 1 1 n n n中间的值且 p i pi pi不能重复。

思路:

对于第一问:

n n n为奇数无解,因为当 n n n为奇数时,一定有 k k k位偶数, k + 1 k+1 k+1位奇数,那么一定有一个为奇数放在为奇数的 i i i上,其二进制最后一位的与运算不为 0 0 0

n n n为偶数时,对于二进制位 11001 11001 11001的数,我们要找到对应的 00110 00110 00110,可以看出前者为 2 k + i 2^k+i 2k+i,后者为 2 k − i − 1 2^k-i-1 2ki1,对应枚举即可。

对于第二问:

n n n小于 6 6 6时,我们分析可知一定无解。

n n n 6 6 6或者 7 7 7时,我们输出特定的解。

n n n 2 2 2的幂时,一定无解,因为对于最后一位 i i i,也就是 2 2 2 n n n次幂,其上放的数一定小于 2 2 2 n n n次幂,对应的二进制比 2 2 2 n n n次幂短,运算后一定为 0 0 0,因为最高位此数为 0 0 0,其余位 i i i上的二进制为 0 0 0

n n n不为 2 2 2的幂时,我们把 1 1 1 n n n分为若干组: 1 1 1 7 7 7一组, 8 8 8 15 15 15一组 . . . ... ... 2 k 2^k 2k 2 k + 1 − 1 2^{k+1}-1 2k+11一组,余下的一组。
对于第一组,我们输出特定的解,对于剩余组,我们任意输出,只要满足 p i pi pi不等于 i i i即可,因为一定在最高位都为 1 1 1,所以与运算一定不为 0 0 0

代码:

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 10;
int vis[MAXN];

int main() {
    int n, y = 1;
    scanf("%d", &n);
    while ((y << 1) <= n) y <<= 1;
    if (n & 1) puts("NO");
    else {
        puts("YES");
        int t = y;
        for (int i = n; i >= 1; i--) {
            if (t > i) t >>= 1;
            if (!vis[i]) {
                int x = t - (i - t) - 1;
                vis[i] = x;
                vis[x] = i;
            }
        }
        for (int i = 1; i <= n; i++) printf("%d ", vis[i]);
        puts("");
    }
    if (n == y || n < 6) puts("NO");
    else {
        puts("YES");
        if (n == 6) puts("3 6 2 5 1 4");
        else {
            printf("7 3 6 5 1 2 4 ");
            for (int i = 8; i <= n;) {
                int j = min(i << 1, n + 1);
                for (int k = i; k < j - 1; k++) printf("%d ", k + 1);
                printf("%d ", i);
                i = j;
            }
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值