1. 程式人生 > 實用技巧 >Educational Codeforces Round 94 (Rated for Div. 2)

Educational Codeforces Round 94 (Rated for Div. 2)

A - String Similarity
可以發現,string裡面的最後一位每一次都會被遍歷到,所以將res全部變成最後一位即可。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>
#include<cstdio>
#include <iomanip>
#pragma GCC optimize(2)
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
	char ch = getchar(); ll x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
int T, n;
char s[101];
int main() {
	T = read();
	while (T--) {
		n = read();
		cin >> s;
		char c = s[n - 1];
		upd(i, 0, n - 1)printf("%c", c);
		cout << endl;
	}
	return 0;
}

B - RPG Protagonist
貪心。列舉一個人選取的S或者W,那麼另外一個就可以貪心的計算出來。
對於另外一個人而言,他應該優先選取更小的那一個。還需要動態維護兩個數量。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>
#include<cstdio>
#include <iomanip>
#pragma GCC optimize(2)
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
	char ch = getchar(); ll x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
const int N = 2e5 + 10;
int T;
ll p, f;
ll cnts, cntw;
ll s, w;
int main() {
	T = read();
	while (T--) {
		p = read(), f = read();
		if (p < f)swap(p, f);
		cnts = read(), cntw = read();
		s = read(), w = read();
		if (s > w) {
			swap(cnts, cntw);
			swap(s, w);
		}
		ll ans = 0;
		upd(i, 0, cnts) {
			ll need = i * s;
			if (need > p)break;
			ll temp = i;
			ll temp2 = (p - need) / w;
			temp += temp2;
			ll temp3 = min(f / s, cnts - i);
			ll temp4 = min(cntw - temp2, (f - temp3 * s) / w);
			temp += temp3 + temp4;
			ans = max(ans, temp);
		}
		cout << ans << endl;
	}
	return 0;
}

C - Binary String Reconstruction
關注答案字串中0的位置,他只能由左右兩邊同時為0構成。所以我們優先處理0的位置,並且將其他剩餘位置全部賦值成1。最後在計算一次是否符合題意。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>
#include<cstdio>
#include <iomanip>
#pragma GCC optimize(2)
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
	char ch = getchar(); ll x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
const int N = 1e5 + 10;
int T;
int x;
char s[N];
char res[N];
bool check(int n) {
	upd(i, 1, n) {
		if (s[i] == '1') {
			bool flag1 = 0;
			if (i - x >= 1) {
				if (res[i - x] == '1')flag1 = 1;
			}
			if (i + x <= n)if (res[i + x] == '1')flag1 = 1;
			if (flag1 == 0)return 0;
		}
	}
	return 1;
}
int main() {
	T = read();
	while (T--) {
		int n;
		scanf("%s", s + 1);
		n = strlen(s + 1);
		upd(i, 0, n)res[i] = 0;
		x = read();
		upd(i, 1, n) {
			if (s[i] == '0') {
				res[max(0, i - x)] = '0';
				res[min(n + 1, i + x)] = '0';
			}
		}
		upd(i, 1, n)if (res[i] == 0)res[i] = '1';
		res[n + 1] = '\0';
		if (check(n)) {
			printf("%s\n", res + 1);
		}
		else printf("%d\n", -1);
	}
}

D - Zigzags
列舉\(i\)\(j\),題目轉換成找到\(k<l,a[k]=a[i],a[j]=a[l]\)。所以我們需要高效的查詢,\(j\)位置後面,滿足題意的\(pair(k,l)\)的數量。
\(sum[i][j]\)表示\(a[i']==i,a[j']==j\)有多少對滿足題意,我們從後往前列舉,不斷維護該陣列,就可以找到滿足題意的\(pair\)。所以我們需要先預處理出,對於位置\(i\)來說,(\(nxt[i][a[j']]\)表示\(i\)後面值為\(a[j']\)\(i\)後面接的數字的數量。那麼每一次轉移就有:\(sum[a[i+1]][j]+=nxt[i+1][j]\)

																						  #include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>
#include<cstdio>
#include <iomanip>
#pragma GCC optimize(2)
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
	char ch = getchar(); ll x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
const int N = 3e3 + 10;
int T, n;
ll a[N];
ll nxt[N][N];
ll suf[N][N];
int main() {
	T = read();
	while (T--) {
		n = read();
		upd(i, 0, n + 1)upd(j, 0, n + 1)nxt[i][j] = suf[i][j] = 0;
		upd(i, 1, n)a[i] = read();
		dwd(i, n, 1) {
			upd(j, 1, 3000) {
				nxt[i][j] = nxt[i + 1][j];
			}
			nxt[i][a[i + 1]]++;
		}
		ll ans = 0;
		dwd(i, n-1, 1) {
			upd(j, 1, 3000)
				suf[a[i + 1]][j] += nxt[i + 1][j];
			dwd(j, i - 1, 1) {
				ans += suf[a[j]][a[i]];
			}
		}
		printf("%lld\n", ans);
	}
	return 0;
}

E - Clear the Multiset
如果對於一段區間\(l,r\),我們採用了操作1(整體減少1),那麼一定會將最小值減少到0。不然的話不會比操作二更優秀。
所以我們發現,對於一段\(l,r\)而言,答案最多是\(r-l+1\)。進行操作1,將區間某一些位置變成0,這個時候我們得到了一些分開的單獨的區間,利用分治,我們繼續進入區間進行計算即可。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>
#include<cstdio>
#include <iomanip>
#pragma GCC optimize(2)
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
	char ch = getchar(); ll x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
const int N = 5e3 + 10;
int a[N];
int n;
int dp(int l, int r) {
	if (r < l)return 0;
	int mn = 1e9 + 1;
	int pos = 0;
	upd(i, l, r)
	{
		if (mn > a[i]) {
			mn = a[i]; pos = i;
		}
	}
	upd(i, l, r)a[i] -= mn;
	return min(dp(l, pos - 1) + dp(pos + 1, r) + mn, r - l + 1);
}
int main() {
	n = read();
	upd(i, 1, n) {
		a[i] = read();
	}
	cout<<dp(1, n);
}

F - x-prime Substrings
預處理出,是x-prime的所有字串。可以通過打表發現,最多2500個。插入到trie數中,最多10000個點。
題目轉換成,給出一些字串,在原串不能出現這些字串。這就和ac自動機的一些裸題很類似了。(構建\(trie\)圖)
\(dp[i][j]\)表示,做到原字串第\(i\)位,在\(tire\)圖上\(j\)狀態的最小代價。(\(trie\)圖上任意狀態都有轉移狀態)
如果有刪除
\(dp[i+1][j]=min(dp[i+1][j],dp[i][j]+1)\)
沒有刪除,並且下一個狀態不是非法狀態
\(dp[i+1][j']=min(dp[i+1][j'],dp[i][j])(j'=tire.ch[j][s[i]-'0])\)

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
#include<regex>
#include<cstdio>
#include <iomanip>
#pragma GCC optimize(2)
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
	char ch = getchar(); ll x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
const int N = 1010;
vector<int>vec;
char s[N];
int x;
struct trie {
	int ch[N * 10][15];
	int flag[N * 10];
	int fail[N * 10];
	int cnt = 0;
	void insert() {
		/*for (auto k : vec)cout << k;
		cout << endl;*/
		int len = vec.size();
		int root = 0;
		up(i, 0, len) {
			int c = vec[i];
			if (!ch[root][c])
				ch[root][c] = ++cnt;
			root = ch[root][c];
		}
		//cout << this->cnt << endl;
		flag[root] = 1;
	}
	void getfail() {
		int root = 0;
		fail[root] = -1;
		queue<int>q;
		up(i, 0, 10)
			if (ch[root][i])q.push(ch[root][i]);
		while (!q.empty()) {
			int top = q.front();
			q.pop();
			up(i, 0, 10) {
				int v = ch[top][i];
				if (!v)ch[top][i] = ch[fail[top]][i];
				else {
					q.push(v);
					fail[v] = ch[fail[top]][i];
					flag[v] |= flag[fail[v]];
				}
			}
		}
	}
}T;
void dfs(int sum) {
	if (sum > x)return;
	if (sum == x) {
		up(i, 0, vec.size()) {
			int summ = 0;
			dwd(j, i, 0) {
				summ += vec[j];
				if (summ != x) {
					if (x%summ == 0)return;
				}
			}
		}
		T.insert();
		return;
	}
	upd(i, 1, 9) {
		vec.push_back(i);
		dfs(sum + i);
		vec.pop_back();
	}
}
int dp[N][N * 10];
void test(int n) {
	cout << T.cnt << endl;
	for (int i = 0; i <= n; i++) {
		for (int j = 0; j <= T.cnt; ++j) {
			printf("%d ", dp[i][j]);
		}
		cout << endl;
	}
}
int main() {
	cin >> s;
	x = read();
	dfs(0);
	T.getfail();
	int n = strlen(s);
	memset(dp, INF, sizeof(dp));
	dp[0][0] = 0;
	up(i, 0, n) {
		upd(j, 0, T.cnt) {
			if (dp[i][j]>=INF)continue;
			dp[i + 1][j] = min(dp[i + 1][j], dp[i][j] + 1);
			int c = T.ch[j][s[i] - '0'];
			if (T.flag[c])continue;
			dp[i + 1][c] = min(dp[i + 1][c], dp[i][j]);
		}
	}
	int ans = INF;
	//test(n);
	upd(j, 0, T.cnt)
		ans = min(ans, dp[n][j]);
	cout << ans << endl;
	return 0;
}