Codeforces Round #604 (Div. 2) D、E、F题解

Beautiful Sequence

[Time Limit: 1000 msquad Memory Limit: 256 MB ]

首先我们可以考虑到 (0) 只能 和 (1) 放在一起、(3) 只能和 (2) 放在一起,那么我们想办法先把 (0)(3) 凑出来,最后就剩下 (1)(2) 了,我们只要把他们放在一起就可以了。

所以我们可以贪心考虑三个 (string),分别长成 (0101...0101)(2323...2323)(1212...1212) 这样的,那么现在的问题就是把这三个 (string) 合并起来,那么完全可以把他们全排列并二进制枚举每个 (string) 是否翻转,然后 (check) 一遍。

view
#include <map>
#include <set>
#include <list>
#include <ctime>
#include <cmath>
#include <stack>
#include <queue>
#include <cfloat>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define  lowbit(x)  x & (-x)
#define  mes(a, b)  memset(a, b, sizeof a)
#define  fi         first
#define  se         second
#define  pb         push_back
#define  pii        pair<int, int>
#define  INOPEN     freopen("in.txt", "r", stdin)
#define  OUTOPEN    freopen("out.txt", "w", stdout)

typedef unsigned long long int ull;
typedef long long int ll;
const int    maxn = 2e5 + 10;
const int    maxm = 1e5 + 10;
const ll     mod  = 1e9 + 7;
const ll     INF  = 1e18 + 100;
const int    inf  = 0x3f3f3f3f;
const double pi   = acos(-1.0);
const double eps  = 1e-8;
using namespace std;

int n, m;
int cas, tol, T;
int a, b, c, d;

string s[4], ss;

bool ok(string a, string b, string c) {
	int lena = a.size(), lenb = b.size(), lenc = c.size();
	int len = lena+lenb+lenc;
	for(int i=0; i<7; i++) {
		if(i&(1<<(0))) {
			reverse(a.begin(), a.end());
		}
		if(i&(1<<(1))) {
			reverse(b.begin(), b.end());
		}
		if(i&(1<<(2))) {
			reverse(c.begin(), c.end());
		}
		ss = a+b+c;
		if(i&(1<<(0))) {
			reverse(a.begin(), a.end());
		}
		if(i&(1<<(1))) {
			reverse(b.begin(), b.end());
		}
		if(i&(1<<(2))) {
			reverse(c.begin(), c.end());
		}

		int flag = 1;
		for(int i=1; i<len; i++) {
			if(abs(ss[i]-ss[i-1])!=1) {
				flag = 0;
				break;
			}
		}
		if(flag) {
			printf("YES
");
			for(int i=0; i<len; i++) {
				printf("%c%c", ss[i], i==len-1 ? '
':' ');
			}
			return true;
		}
	}
	return false;
}

int main() {
	scanf("%d%d%d%d", &a, &b, &c, &d);
	s[1] = "";
	while(a&&b) {
		s[1] += "01";
		a--, b--;
	}
	if(a) {
		s[1] += "0";
		a--;
	}
	if(b) {
		s[1] = "1"+s[1];
		b--;
	}

	s[3] = "";
	while(c&&d) {
		s[3] += "23";
		c--, d--;
	}
	if(c) {
		s[3] += "2";
		c--;
	}
	if(d) {
		s[3] = "3"+s[3];
		d--;
	}
	
	s[2] = "";
	while(b&&c) {
		s[2] += "12";
		b--, c--;
	}
	if(b) {
		s[2] += "1";
		b--;
	}
	if(c) {
		s[2] = "2"+s[2];
		c--;
	}
	if(a||b||c||d)	return 0*puts("NO");
	do {
		if(ok(s[1], s[2], s[3]))
			return 0;
	} while(next_permutation(s+1, s+1+3));
	puts("NO");
	return 0;
}

Beautiful Mirrors

[Time Limit: 2000 msquad Memory Limit: 256 MB ]

首先令 (dp[i]) 表示从第 (i) 天到结束所需要的期望天数,为了方便,可以假设 (n+1) 天为结束位置,那么 (dp[n+1] = 0)

对于 (1<=i<=n),有 (dp[i] = frac{p_i*dp[i+1] + (100-p_i)*dp[1]}{100}+1)

然后一直带进去,最后可以发现 (dp[1]) 可以表示为

[ dp[1] = A*dp[1] + B + 1 ]

其中 (A、B) 都是具体的数字,那么就得到的 (dp[1]) 的值。

view
#include <map>
#include <set>
#include <list>
#include <ctime>
#include <cmath>
#include <stack>
#include <queue>
#include <cfloat>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define  lowbit(x)  x & (-x)
#define  mes(a, b)  memset(a, b, sizeof a)
#define  fi         first
#define  se         second
#define  pb         push_back
#define  pii        pair<int, int>
#define  INOPEN     freopen("in.txt", "r", stdin)
#define  OUTOPEN    freopen("out.txt", "w", stdout)
 
typedef unsigned long long int ull;
typedef long long int ll;
const int    maxn = 2e5 + 10;
const int    maxm = 1e5 + 10;
const ll     mod  = 998244353;
const ll     INF  = 1e18 + 100;
const int    inf  = 0x3f3f3f3f;
const double pi   = acos(-1.0);
const double eps  = 1e-8;
using namespace std;
 
int n, m;
int cas, tol, T;
 
int p[maxn];
 
ll fpow(ll a, ll b) {
	ll ans = 1;
	while(b) {
		if(b&1)	ans = ans*a%mod;
		 a = a*a%mod;
		 b >>= 1;
	}
	return ans;
}
 
int main() {
	ll M = fpow(100ll, mod-2);
	scanf("%d", &n);
	for(int i=1; i<=n; i++) {
		scanf("%d", &p[i]);
	}
	ll b = 0, c = 0;
	ll tmpb = 1;
	for(int i=1; i<=n; i++) {
		b += tmpb*(100ll-p[i])%mod*M%mod;
		c += tmpb;
		tmpb *= p[i]*M%mod;
		b %= mod, c %=mod, tmpb %= mod;
	}
	b = mod-b+1;
	b = (b%mod+mod)%mod;
	ll ans = c*fpow(b, mod-2)%mod;
	printf("%lld
", ans);
	return 0;
}

Beautiful Bracket Sequence (easy version)

[Time Limit: 2000 msquad Memory Limit: 256 MB ]

(dp[i][j]) 表示从 (i)(j) 区间内,所有情况的括号最深深度之和。

转移的时候令 (dp[i][i] = 0)(dp[i][i+1])(s[i])(s[i+1]) 能否组成 (())

对于更大的区间,只需要考虑最左和最右端点就可以。

  1. 如果(s[i]) 可以放成 (()

    • 如果 (s[j]) 可以放成 (()(dp[i][j] += dp[i][j-1])
    • 如果 (s[j]) 可以放成 ())(dp[i][j] += dp[i+1][j-1] + 2^k)(k) 代表 ([i+1,j-1]) 这段内 (?) 的个数。
  2. 如果 (s[i]) 可以放成 ())

    • 如果 (s[j]) 可以放成 (()(dp[i][j] += dp[i+1][j-1])
    • 如果 (s[j]) 可以放成 ())(dp[i][j] += dp[i+1][j])

然后有一部分会被重复计算,也就是 (dp[i+1][j-1]) 这一段,所以只要顺便记录一下转移过程中计算了几次这一段,然后扣掉多计算的就可以了。

view
#include <map>
#include <set>
#include <list>
#include <ctime>
#include <cmath>
#include <stack>
#include <queue>
#include <cfloat>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define  lowbit(x)  x & (-x)
#define  mes(a, b)  memset(a, b, sizeof a)
#define  fi         first
#define  se         second
#define  pb         push_back
#define  pii        pair<int, int>
#define  INOPEN     freopen("in.txt", "r", stdin)
#define  OUTOPEN    freopen("out.txt", "w", stdout)
 
typedef unsigned long long int ull;
typedef long long int ll;
const int    maxn = 2e3 + 10;
const int    maxm = 1e5 + 10;
const ll     mod  = 998244353;
const ll     INF  = 1e18 + 100;
const int    inf  = 0x3f3f3f3f;
const double pi   = acos(-1.0);
const double eps  = 1e-8;
using namespace std;
 
int n, m, TT;
int cas, tol;
 
int a[maxn] = {0};
char s[maxn];
ll dp[maxn][maxn];
 
ll fpow(ll a, ll b) {
	ll ans = 1;
  	while(b) {
		if(b&1)	ans = ans*a%mod;
		a = a*a%mod;
		b >>= 1;
	}
	return ans;
}
 
int main() {
	scanf("%s", s+1);
	n = strlen(s+1);
	for(int i=1; i<=n; i++) {
		a[i] = a[i-1]+(s[i]=='?');
		dp[i][i] = 0;
		dp[i][i+1] = (i+1<=n && s[i]!=')' && s[i+1]!='(');
	}
	for(int d=3; d<=n; d++) {
		for(int i=1, j=d, c; j<=n; i++, j++) {
			dp[i][j] = 0, c = -1;
			if(s[i] != ')') {
				if(s[j] != ')')	dp[i][j] += dp[i][j-1], c++;
				if(s[j] != '(')	dp[i][j] += dp[i+1][j-1] + fpow(2, a[j-1]-a[i]);
			}
			if(s[i] != '(') {
				if(s[j] != ')')	dp[i][j] += dp[i+1][j-1], c++;
				if(s[j] != '(')	dp[i][j] += dp[i+1][j], c++;
			}
			dp[i][j] -= max(c, 0)*dp[i+1][j-1];
			dp[i][j] %= mod;
//			printf("dp[%d][%d] = %lld
", i, j, dp[i][j]);
		}
	}
	printf("%lld
", dp[1][n]);
    return 0;
}
原文地址:https://www.cnblogs.com/Jiaaaaaaaqi/p/12037553.html