Codeforces Round #553 (Div. 2) 题解

题目链接

A. Maxim and Biology

取连续一段改为ACTG的最小代价

#include <stdio.h>
#include <bits/stdc++.h>
#define fst first
#define sed second
using namespace std;
typedef long long ll;

const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
char s[100], c[] = "ACTG";

int dis(char a, char b)
{
	a = a - 'A', b = b - 'A';
	return min((a - b + 26) % 26, (b - a + 26) % 26);
}
int main()
{
#ifdef LOCAL
	//freopen("C:/input.txt", "r", stdin);
#endif
	int n;
	cin >> n >> s;
	int ans = INF;
	for (int i = 0; i < n - 3; ++i)
	{
		int cnt = 0;
		for (int j = 0; j < 4; ++j)
			cnt += dis(s[i + j], c[j]);
		ans = min(ans, cnt);
	}
	cout << ans << endl;

	return 0;
}

B. Dima and a Bad XOR <思维>

矩阵每行选一个数字异或和不为0

#include <stdio.h>
#include <bits/stdc++.h>
#define fst first
#define sed second
using namespace std;
typedef long long ll;

const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int N = 510;
int g[N][N];

int main()
{
#ifdef LOCAL
	//freopen("C:/input.txt", "r", stdin);
#endif
	int n, m, x = 0;
	cin >> n >> m;
	for (int i = 1; i <= n; ++i)
	{
		for (int j = 1; j <= m; ++j)
			scanf("%d", &g[i][j]);
		x ^= g[i][1];
	}
	if (x)
	{
		cout << "TAK" << endl;
		for (int i = 1; i <= n; ++i)
			cout << "1 ";
		cout << endl, exit(0);
	}
	for (int i = 1; i <= n; ++i)
		for (int j = 2; j <= m; ++j)
		{
			x ^= g[i][j - 1] ^ g[i][j];
			if (x)
			{
				cout << "TAK" << endl;
				for (int k = 1; k < i; ++k)
					cout << "1 ";
				cout << j << " ";
				for (int k = i + 1; k <= n; ++k)
					cout << "1 ";
				cout << endl, exit(0);
			}
		}
	cout << "NIE" << endl;

	return 0;
}

C. Problem for Nazar <模拟> <复杂度分析>

给定一个序列1/2 4/3 5 7 9/6 8 10。。奇数偶数交替且长度增加一倍 问第l到r项的和

#include <stdio.h>
#include <bits/stdc++.h>
#define fst first
#define sed second
using namespace std;
typedef long long ll;

const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int MOD = 1e9 + 7;

ll calc(ll x) //logn计算1~x项和
{
	ll res = 0;
	ll v[2] = { 2, 1 }, w = 1; //奇偶当前数值 项数
	for (int i = 1; x; i = (i + 1) % 2, w *= 2)
	{
		res = (res + (v[i] + v[i] + (min(x, w) - 1) * 2LL) % MOD * (min(x, w) % MOD) % MOD * 500000004LL) % MOD; //等差数列求和 除法逆元注意炸ll
		v[i] = (v[i] + w * 2LL) % MOD;
		x -= min(x, w);
	}
	return res;
}
int main()
{
#ifdef LOCAL
	//freopen("C:/input.txt", "r", stdin);
#endif
	ll l, r;
	cin >> l >> r;
	cout << (calc(r) - calc(l - 1) + MOD) % MOD << endl;

	return 0;
}

D. Stas and the Queue at the Buffet <贪心>

每个人有两个参数a和b 这个人的不满意度为他前面人数量a+后面人数量b 问整个队列最小不满意度

#include <stdio.h>
#include <bits/stdc++.h>
#define fst first
#define sed second
using namespace std;
typedef long long ll;

const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e5 + 10;

struct node
{
	ll a, b, i;
	bool operator < (const node &o) const
	{
		return a - b > o.a - o.b;
	}
}a[N];
int main()
{
#ifdef LOCAL
	//freopen("C:/input.txt", "r", stdin);
#endif
	int n;
	cin >> n;
	for (int i = 1; i <= n; ++i)
		scanf("%I64d%I64d", &a[i].a, &a[i].b), a[i].i = i;
	sort(a + 1, a + n + 1);
	ll ans = 0;
	for (int i = 1; i <= n; ++i)
		ans += a[i].a * (i - 1) + a[i].b * (n - i);
	cout << ans << endl;

	return 0;
}

E. Number of Components <贡献>

给n个数字 位置相邻的两个数字之间有一条连线 f(l,r)表示只保留数值范围[l,r]节点的强连通分量数 函数f(1<=l<=r<=n)所有取值的和
计算每个点产生贡献的区间[l, r],如当前点值为a[i]则1<=l<=a[i]<=r<=n,但是如果左侧的点存在l和r的取值范围就会有些限制。
调整lr后,l和r的取值范围相乘就是当前点的贡献。

#include <stdio.h>
#include <bits/stdc++.h>
#define fst first
#define sed second
using namespace std;
typedef long long ll;

const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e5 + 10;
ll a[N];

int main()
{
#ifdef LOCAL
	//freopen("C:/input.txt", "r", stdin);
#endif
	int n;
	cin >> n;
	for (int i = 1; i <= n; ++i)
		scanf("%I64d", &a[i]);
	ll ans = 0;
	for (int i = 1; i <= n; ++i)
	{
		ll l = a[i], r = n - a[i] + 1;
		if (a[i - 1] <= a[i])
			l = min(l, a[i] - a[i - 1]);
		else
			r = min(r, a[i - 1] - a[i]);
		ans += l * r;
	}
	cout << ans << endl;

	return 0;
}

F. Sonya and Informatics <dp> <矩阵优化> <组合数>

一个01串等概率随机选取两个不同的位置进行交换 k次操作后问串为非递减序列的概率
参考大佬博客

#include <stdio.h>
#include <bits/stdc++.h>
#define fst first
#define sed second
using namespace std;
typedef long long ll;

const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int MOD = 1e9 + 7;
const int N = 110;
int C[N][N];
int a[N];
//ll f[N][N]; //f[i][j]表示i次操作j个0不在应该在的位置上

ll qpow(ll a, ll n, ll m)
{
	ll res = 1;
	while (n)
	{
		if (n & 1)
			res = res * a % m;
		a = a * a % m;
		n >>= 1;
	}
	return res;
}
struct Matrix
{
	ll m[N][N];
	static const int N = 50; //阶数
	Matrix(int v = 0)
	{
		memset(m, 0, sizeof(m));
		if (v)
			for (int i = 0; i < N; i++)
				m[i][i] = v;
	}
	Matrix operator * (const Matrix &b)
	{
		Matrix t;
		for (int i = 0; i < N; i++)
			for (int j = 0; j < N; j++)
				for (int k = 0; k < N; k++)
					t.m[i][j] = (t.m[i][j] + m[i][k] * b.m[k][j]) % MOD;
		return t;
	}
	friend Matrix operator ^ (Matrix a, int n)
	{
		Matrix t(1);
		while (n)
		{
			if (n & 1)
				t = t * a;
			a = a * a;
			n >>= 1;
		}
		return t;
	}
}tran, x; //x[0][i]表示当前状态有i个0/1不在应该在的位置上
int main()
{
#ifdef LOCAL
	freopen("C:/input.txt", "r", stdin);
#endif
	C[0][0] = 1;
	for (int i = 1; i < N; i++)
	{
		C[i][0] = 1;
		for (int j = 1; j < N; j++)
			C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % MOD;
	}
	int n, k, z = 0; //0个数
	cin >> n >> k; 
	for (int i = 1; i <= n; ++i)
		scanf("%d", &a[i]), z += !a[i];
	int p = 0; //位置不对的个数 位置不对的1=位置不对的0
	for (int i = 1; i <= z; ++i)
		p += a[i];
	/*
	f[0][p] = 1;
	int m = min(z, n - z), den = qpow(C[n][2], MOD - 2, MOD); //den总情况
	for (int i = 0; i < k; ++i) //操作
		for (int j = 0; j <= m; ++j) //不对的数量不会超过某个的数量
		{
			if (j) //交换后位置不对数量-1
				f[i + 1][j - 1] = (f[i + 1][j - 1] + f[i][j] * j * j * den) % MOD; //0不对*1不对
			if (j < m) //数量+1
				f[i + 1][j + 1] = (f[i + 1][j + 1] + f[i][j] * (z - j) * (n - z - j) * den) % MOD; //0对*1对
			f[i + 1][j] = (f[i + 1][j] + f[i][j] * (C[z][2] + C[n - z][2] + (z - j) * j + (n - z - j) * j) * den) % MOD;
		}
	cout << f[k][0] << endl;
	*/
	x.m[0][p] = 1; //初始状态100%
	ll m = min(z, n - z), den = qpow(C[n][2], MOD - 2, MOD); //den总情况
	for (int i = 0; i <= m; ++i) //不对的数量 不会超过某个的数量
	{
		int j;
		if (i) //由i-1增加1个转移来
		{
			j = i - 1; //上个状态
			tran.m[i - 1][i] = (z - j) * (n - z - j) * den % MOD; //0对*1对
		}
		tran.m[i][i] = (C[z][2] + C[n - z][2] + (z - i) * i + (n - z - i) * i) * den % MOD; //0/1交换 同侧01/10交换
		if (i < m) //由i+1减少1个转移来
		{
			j = i + 1;
			tran.m[i + 1][i] = j * j * den % MOD; //0不对*1不对
		}
	}
	x = x * (tran ^ k);
	cout << x.m[0][0] << endl; //输出全对情况

	return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值