Codeforces Round #848 (Div. 2)

A. Flip Flop Sum

题意:

给定长度为 n n n 的只包括 − 1 -1 1 1 1 1 的序列。进行一次操作:选定 i i i ,使 a i a_i ai a i + 1 a_{i+1} ai+1 变为相反数。询问操作一次后,序列的和的最大值

解析:

如果选择的两个数均为 − 1 -1 1 ,会使和增加 4 4 4;
如果选择的两个数一个是 1 1 1 ,一个是 − 1 -1 1,和不变;
如果选择的两个数均为 1 1 1,会使和减小 4 4 4

代码:

#include
using namespace std;
#define fi first
#define se second
const int maxn = 1e5+10;
const int INF = 0x3f3f3f3f;
typedef long long ll;
typedef double db;
typedef pair<int, int> pii;

int n;
int a[maxn];
void solve(){
	cin >> n;
	int sum = 0;
	for(int i = 1; i <= n; i++){
		cin >> a[i];
		sum += a[i];
	}
	int flag1 = 0, flag2 = 0;
	for(int i = 2; i <= n; i++){
		if(a[i] == -1 && a[i-1] == -1){
			flag1 = 1;
			break;
		}
		if(a[i] != a[i-1])
			flag2 = 1;	
	}
	if(flag1)
		sum += 4;
	else if(!flag2)
		sum -= 4;
	//cout << "ans = " ; 
	cout << sum << endl;
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	
	int T;
	cin >> T;
	while(T--)
		solve();
	return 0;
}


B. The Forbidden Permutation

题意:

给定长度为 n n n 的一个排列 p p p,大小为 m m m 的数组 a a a a a a 中元素互不相同

数组 a a a不好的 当且仅当 对任意 1 ≤ i < m 1\le i < m 1i<m ,都有 p o s ( a i ) < p o s ( a i + 1 ) ≤ p o s ( a i ) + d pos(a_i) < pos(a_{i+1}) \le pos(a_i)+d pos(ai)<pos(ai+1)pos(ai)+d p o s ( x ) pos(x) pos(x) x x x 在排列 p p p 中的位置。

每次操作可以交换排列 p p p 中的两个相邻元素,询问是数组 a a a 成为 好的 的最少操作次数。

解析:

依次考虑每一组 a i a_i ai a i + 1 a_{i+1} ai+1

如果不满足条件,则答案为 0 0 0 ,因为此时数组 a a a 已经是好的;

如果满足条件,通过操作使条件不满足。可以将 a i + 1 a_{i+1} ai+1 放到 a i a_i ai 的前边,操作次数为 p o s ( a i + 1 ) − p o s ( a i ) pos(a_{i+1}) - pos(a_i) pos(ai+1)pos(ai) 。也可以使 a i + 1 a_{i+1} ai+1 放到后边,操作次数为 p o s ( a + i ) + d + 1 − p o s ( a i + 1 ) pos(a+i)+d+1-pos(a_{i+1}) pos(a+i)+d+1pos(ai+1)

特别注意,当 d > = n − 1 d >= n-1 d>=n1 时,无法通过第二种方法使条件不满足

代码:

#include
using namespace std;
#define fi first
#define se second
const int maxn = 5e5+10;
const int INF = 0x3f3f3f3f;
typedef long long ll;
typedef double db;
typedef pair<int, int> pii;

int n, m, d;
int p[maxn], a[maxn], pos[maxn];
void solve(){
	cin >> n >> m >> d;
	int ans = INF;
	for(int i = 1; i <= n; i++){
		cin >> p[i];
		pos[p[i]] = i;
	}		
	for(int i = 1; i <= m; i++)
		cin >> a[i];
	
	for(int i = 1; i < m; i++){
		if(pos[a[i]] < pos[a[i+1]] && pos[a[i+1]] <= pos[a[i]]+d){
			int c1 = pos[a[i+1]]-pos[a[i]];
			int c2 = pos[a[i]]+d+1-pos[a[i+1]];
			if(d >= n-1)
				c2 = INF;
			int c = min(c1, c2);
			ans = min(ans, c);
		}
		else{
			ans = 0;
			break;
		}
	}
	//cout << "ans = ";
	cout << ans << endl;
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	
	int T;
	cin >> T;
	while(T--)
		solve();
	return 0;
}


C. Flexible String

题意:

给定两个长度为 n n n 的字符串 a , b a, b a,b 。其中, a a a 中不同字符个数不超过10个。

给定一个初始空集合 Q Q Q 。每次操作可以选定 i i i,将 a i a_i ai 放到集合 Q Q Q 中,并用任意小写字母代替 a i a_i ai。集合 Q Q Q 中元素个数 不能超过 k k k

询问 ( l , r ) (l,r) (l,r) 的个数, ( l , r ) (l,r) (l,r) 满足 a [ l , r ] = b [ l , r ] a[l,r] = b[l,r] a[l,r]=b[l,r]

解析:

首先看到 a a a 中字符种类不超过 10 10 10,选择 k k k 个的话,最多 C ( 10 , 5 ) = 252 C(10,5) = 252 C(10,5)=252 种情况。
每种情况如果可以在 O ( n ) O(n) O(n) 时间内计算结果的话,就可以解决。

考虑长度为 l e n len len a , b a,b a,b 相同的子串。对答案的贡献为 l e n ( l e n + 1 ) 2 \frac{len(len+1)}{2} 2len(len+1) 。因此,对于每种情况,遍历一次 a , b a,b a,b,计算结果即可。

代码:

#include
using namespace std;
#define fi first
#define se second
const int maxn = 1e5+10;
const int INF = 0x3f3f3f3f;
const int maxs = 1023;
typedef long long ll;
typedef double db;
typedef pair<int, int> pii;

ll f(int x){
	ll res = x;
	return res*(res+1)/2;
}
char a[maxn], b[maxn];
int n, k;
vector<int> s[12];
int cal(int x){
	int cnt = 0;
	while(x){
		if(x&1)
			cnt++;
		x = x >> 1;
	}
	return cnt;
}
void init(){
	for(int i = 0; i <= maxs; i++){
		int cnt = cal(i);
		s[cnt].push_back(i);
		/*
		for(int j = cnt; j <= 10; j++)
			s[j].push_back(i);*/
	}
}
int vis[30];
map<int, int> mp;
bool check(int state, int x){
	if((state & (1<<x)) == 0)
		return false;
	else
		return true;
}
void solve(){
	cin >> n >> k;
	cin >> a+1 >> b+1;
	memset(vis, 0, sizeof(vis));
	mp.clear();
	ll ans = 0;
	for(int i = 1; i <= n; i++){
		int s = a[i]-'a';
		vis[s] = 1;
	}
	for(int i = 0; i <= 25; i++){
		if(!vis[i])
			continue;
		int cnt = 0;
		for(int j = 0; j < i; j++)
			if(vis[j])
				cnt++;
		mp[i] = cnt;
	}
	for(int ii = 0; ii < s[k].size(); ii++){
		int state = s[k][ii];
		int len = 0;
		ll res = 0;
		for(int i = 1; i <= n; i++){
			int x = a[i]-'a';
			if(a[i] == b[i]){
				len++;
			}
			else if(check(state, mp[x])){
				len++;
			}
			else{
				res += f(len);
				len = 0;
			}
		}
		if(a[n] == b[n] || check(state, mp[(int)a[n]-'a']))
			res += f(len);
		ans = max(res, ans);
	}
	//cout << "ans = ";
	cout << ans << endl;
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	
	init();
	int T;
	cin >> T;
	while(T--)
		solve();
	return 0;
}


D. Flexible String Revisit

题意:

给定长度为 n n n 01 01 01 a , b a,b a,b 。每次操作随机选 i i i ,翻转 a i a_i ai

询问 a a a b b b 第一次相等的操作次数的期望

解析:

f i f_i fi 为 由 i − 1 i-1 i1 处相同,变为 i i i 处相同的期望次数。

如果此时有 i i i 处相同。有 n − i n \frac{n-i}{n} nni 概率操作一次;有 i n \frac{i}{n} ni 的选中相同的位置,变成 i − 1 i-1 i1 处相同,然后需要操作 f i + f i + 1 f_i+f_{i+1} fi+fi+1 次变为 i + 1 i+1 i+1 处相同。

因此 f i + 1 = n − i n + i n × ( 1 + f i + f i + 1 ) f_{i+1} = \frac{n-i}{n} +\frac{i}{n}\times(1+f_i+f_{i+1}) fi+1=nni+ni×(1+fi+fi+1)

整理得: f i + 1 = 1 + i n − i × ( 1 + f i ) f_{i+1} = 1+\frac{i}{n-i}\times(1+f_i) fi+1=1+nii×(1+fi)

如果初始 a a a b b b k k k 处相同,答案为 ∑ i = k + 1 n f i \sum\limits_{i=k+1}\limits^nf_i i=k+1nfi

代码:

#include
using namespace std;
#define fi first
#define se second
const int maxn = 1e6+10;
const int INF = 0x3f3f3f3f;
const int mod = 998244353;
typedef long long ll;
typedef double db;
typedef pair<int, int> pii;


ll qpow(ll a, ll b){
	ll res = 1;
	while(b){
		if(b&1)
			res = res*a%mod;
		b = b >> 1;
		a = a*a%mod;
	}
	return res%mod;
}
ll inv(ll a){
	return qpow(a, mod-2);
}
ll f[maxn];
char a[maxn], b[maxn];
void solve(){
	int n;
	cin >> n;
	cin >> a+1 >> b+1;
	ll sam = 0;
	for(int i = 1; i <= n; i++)
		if(a[i] == b[i])
			sam++;
	f[1] = 1;
	for(int i = 1; i < n; i++){
		f[i+1] = 1 + i*inv(n-i)%mod*(f[i]+1);
		f[i+1] %= mod;
	}
	ll sum = 0;
	for(int i = sam+1; i <= n; i++){
		sum += f[i];
		sum %= mod;
	}
	sum = ((sum%mod)+mod)%mod;
	cout << sum << endl; 
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	
	int T;
	cin >> T;
	while(T--)
		solve(); 
	return 0;
}

你可能感兴趣的:(codeforces,算法,c++,贪心算法)