Codeforces Edu Round #94 (CF1400)
掉了点分
A:
给定长度为\(2n-1\)的01字符串\(str\),求长度为\(n\)的字符串\(ans\),使得\(ans \sim str\)。
定义字符串\(a \sim b\)时,有\(i\)满足\(a_i = b_i\)。
一道ca大水题,有两种解法:
-
/* ID: Loxilante Time: 2020/08/27 Prog: CF1400A-1 Lang: cpp */ #ifdef ONLINE_JUDGE #pragma GCC optimize("O3") #endif #include <bits/extc++.h> #define rep(i, l, r) for(int i = l; i < r; i++) #define hrp(i, l, r) for(int i = l; i <= r; i++) #define rev(i, r, l) for(int i = r; i >= l; i--) #define ms(n, t) memset(n, t, sizeof(n)) #define pb push_back #define int ll #ifndef JOEON #define D(...) 97 #endif using namespace std; typedef long long ll; typedef pair<int, int> pii; template<typename tn = int> inline tn next(void) { tn k; cin>>k; return k; } signed main(void) { clock_t Begin = clock(); #ifdef JOEON // freopen("C:\\Users\\Joeon\\Desktop\\IN.txt", "r", stdin); // freopen("C:\\Users\\Joeon\\Desktop\\OUT.txt", "w", stdout); #endif ios::sync_with_stdio(false); cin.tie(0); int T = next(); clock_t InputFinished = clock(); while(T--) { int n = next(); string str = next<string>(); rep(i, 0, n) cout<<str[n-1]; cout<<endl; } clock_t End = clock(); D((double)(End-Begin)/CLOCKS_PER_SEC); D((double)(End-InputFinished)/CLOCKS_PER_SEC); return 0; }
-
/* ID: Loxilante Time: 2020/08/25 Prog: CF1400A Lang: cpp */ #ifdef ONLINE_JUDGE #pragma GCC optimize("O3") #endif #include <bits/extc++.h> #define rep(i, l, r) for(int i = l; i < r; i++) #define hrp(i, l, r) for(int i = l; i <= r; i++) #define rev(i, r, l) for(int i = r; i >= l; i--) #define ms(n, t) memset(n, t, sizeof(n)) #define pb push_back #define int ll #ifndef JOEON #define D(...) 97 #endif using namespace std; typedef long long ll; typedef pair<int, int> pii; template<typename tn = int> inline tn next(void) { tn k; cin>>k; return k; } signed main(void) { clock_t Begin = clock(); #ifdef JOEON // freopen("C:\\Users\\Joeon\\Desktop\\IN.txt", "r", stdin); // freopen("C:\\Users\\Joeon\\Desktop\\OUT.txt", "w", stdout); #endif ios::sync_with_stdio(false); cin.tie(0); int T = next(); clock_t InputFinished = clock(); while(T--) { int l = next(); string str = next<string>(); for(int i = 0; i < str.length(); i += 2) cout<<str[i]; cout<<endl; } clock_t End = clock(); D((double)(End-Begin)/CLOCKS_PER_SEC); D((double)(End-InputFinished)/CLOCKS_PER_SEC); return 0; }
读者自证不难。
B:
你和随从分别能承重\(p, f\),现有\(cnt_s\)把剑和\(cnt_w\)把斧头,剑重\(s\),斧重\(w\),求最多能拿走多少武器。
考场上花一个小时打\(O(1)\)算法,先\(\color{red}{PigeonGuGuGu}\)着。
下面来考虑\(O(cnts)\)的做法:
假设\(s <= w\),也就是剑比斧重。
枚举自己最多带的剑的数量,算出能带斧的数量。
让随从带尽可能多的剑,如果带完了再带斧头。
Code:
/*
ID: Loxilante
Time: 2020/08/27
Prog: CF1400B
Lang: cpp
*/
#ifdef ONLINE_JUDGE
#pragma GCC optimize("O3")
#endif
#include <bits/extc++.h>
#define rep(i, l, r) for(int i = l; i < r; i++)
#define hrp(i, l, r) for(int i = l; i <= r; i++)
#define rev(i, r, l) for(int i = r; i >= l; i--)
#define ms(n, t) memset(n, t, sizeof(n))
#define pb push_back
#define int ll
#ifndef JOEON
#define D(...) 97
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
template<typename tn = int> inline tn next(void) { tn k; cin>>k; return k; }
signed main(void)
{
clock_t Begin = clock();
#ifdef JOEON
// freopen("C:\\Users\\Joeon\\Desktop\\IN.txt", "r", stdin);
// freopen("C:\\Users\\Joeon\\Desktop\\OUT.txt", "w", stdout);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
int T = next<int>();
clock_t InputFinished = clock();
while(T--)
{
int y, f, cnts, cntw, s, w, ans = 0;
cin>>y>>f>>cnts>>cntw>>s>>w;
if (s > w) swap(cnts, cntw), swap(s, w);
hrp(takeSword, 0, cnts)
{
if (takeSword*s > y) break;
int Y = y, F = f, ret = takeSword;
Y -= takeSword*s; // i take sword
int takeSword2 = min(F/s, cnts-takeSword); // follower take sword
ret += takeSword2;
F -= takeSword2*s;
ret += min(cntw, Y/w+F/w); // take war axe
ans = max(ans, ret);
}
cout<<ans<<endl;
}
clock_t End = clock();
D((double)(End-Begin)/CLOCKS_PER_SEC);
D((double)(End-InputFinished)/CLOCKS_PER_SEC);
return 0;
}
/*
3
33 27
6 10
5 6
100 200
10 10
5 5
1 19
1 3
19 5
*/
C:
考场上读假题,罚时杠杠哒
给定整数\(x\)和字符串\(str\),\(str_i\)等于\(1\)当且仅当\(ans_{i+x}\)或\(ans_{i-x}\)等于\(0\),求字符串\(ans\)。
1500的ca,对于这种ca我们可以直接口胡个greedy水过:
当\(str_i\)等于0时,我们让\(ans_{i \pm x} = 0\),反正没有limit随便瞎搞,不过只有这些这题就配不上1500啦,难点还有\(-1\)。
不过这也很好操作,遍历\(ans\),然后判断是否合法,也就是\(str_i = 1\)时判断\(ans_{i \pm x}\)是否等于0,如果等于就输出\(-1\),1500的ca就是这么好水。
Code:
/*
ID: Loxilante
Time: 2020/08/26
Prog: CF1400C
Lang: cpp
*/
#ifdef ONLINE_JUDGE
#pragma GCC optimize("O3")
#endif
#include <bits/extc++.h>
#define rep(i, l, r) for(int i = l; i < r; i++)
#define hrp(i, l, r) for(int i = l; i <= r; i++)
#define rev(i, r, l) for(int i = r; i >= l; i--)
#define ms(n, t) memset(n, t, sizeof(n))
#define pb push_back
#define int ll
#ifndef JOEON
#define D(...) 97
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
template<typename tn = int> inline tn next(void) { tn k; cin>>k; return k; }
signed main(void)
{
clock_t Begin = clock();
#ifdef JOEON
// freopen("C:\\Users\\Joeon\\Desktop\\IN.txt", "r", stdin);
// freopen("C:\\Users\\Joeon\\Desktop\\OUT.txt", "w", stdout);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
int T = next();
clock_t InputFinished = clock();
while(T--)
{
string str = next<string>();
int x = next();
auto in = [=](const int& e)
{
return 0 <= e && e < str.length();
};
string ans;
rep(i, 0, str.length()) ans += '1';
rep(i, 0, str.length())
{
if (str[i] == '0')
{
int a = i-x, b = i+x;
if (in(a)) ans[i-x] = '0';
if (in(b)) ans[i+x] = '0';
}
}
bool N = 1;
rep(i, 0, str.size())
{
if (str[i] == '1')
{
bool no = 1;
int a = i-x, b = i+x;
if (in(a) && ans[a] == '1') no = 0;
if (in(b) && ans[b] == '1') no = 0;
if (no) {N = 0; break;}
}
}
if (!N) cout<<-1<<endl;
else cout<<ans<<endl;
}
clock_t End = clock();
D((double)(End-Begin)/CLOCKS_PER_SEC);
D((double)(End-InputFinished)/CLOCKS_PER_SEC);
return 0;
}
D:
超级1900大水题,可以用超级ez的dp水过,勉强算个dp吧。
给定数列\(w\),求满足\(w_i == w_k \&\& w_j == w_l (i < j < k < l)\)的个数。
考虑到\(n <= 3000\),可以用\(O(n^2)\)的暴力枚举。
枚举谁呢? \(i, j\) ?不妥,\(w_k\)和\(w_l\)难求。\(etc.\)。感性推断,理性发现,只有枚举\(w_k\)和\(w_j\),这样\(w_i\)和\(w_l\)比较容易知道,也好写。
思路很简单:开一个\(pr\)前缀数组和\(suf\)后缀数组,\(pr_{i,j}\)代表指针i之前等于\(j\)的个数,\(suf_{i,j}\)代表指针i后等于\(j\)的个数,这大概也许应该是个dp吧,既然是dp,就得有个像样的转移方程,于是:
\(pr_{i, j} = pr_{i-1, j} + (j == w[i])\)
\(suf_{i, j} = suf_{i+1, j} + (j == w[i])\)
Code:
/*
ID: Loxilante
Time: 2020/08/26
Prog: CF1400D
Lang: cpp
*/
#ifdef ONLINE_JUDGE
#pragma GCC optimize("O3")
#endif
#include <bits/extc++.h>
#define rep(i, l, r) for(int i = l; i < r; i++)
#define hrp(i, l, r) for(int i = l; i <= r; i++)
#define rev(i, r, l) for(int i = r; i >= l; i--)
#define ms(n, t) memset(n, t, sizeof(n))
#define pb push_back
#define int ll
#ifndef JOEON
#define D(...) 97
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
template<typename tn = int> inline tn next(void) { tn k; cin>>k; return k; }
const int U = 3e3+50;
int pr[U][U], suf[U][U], w[U];
signed main(void)
{
clock_t Begin = clock();
#ifdef JOEON
// freopen("C:\\Users\\Joeon\\Desktop\\IN.txt", "r", stdin);
// freopen("C:\\Users\\Joeon\\Desktop\\OUT.txt", "w", stdout);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
int T = next();
clock_t InputFinished = clock();
while(T--)
{
int n = next(), ans = 0;
rep(i, 0, n) cin>>w[i];
ms(pr, 0);
ms(suf, 0);
rep(i, 0, n)
{
if (i) hrp(j, 0, n) pr[i][j] = pr[i-1][j];
pr[i][w[i]]++;
}
rev(i, n-1, 0)
{
if (i != n-1) hrp(j, 0, n) suf[i][j] = suf[i+1][j];
suf[i][w[i]]++;
}
rep(j, 1, n-2) rep(k, j+1, n-1) ans += pr[j-1][w[k]]*suf[k+1][w[j]];
cout<<ans<<endl;
}
clock_t End = clock();
D((double)(End-Begin)/CLOCKS_PER_SEC);
D((double)(End-InputFinished)/CLOCKS_PER_SEC);
return 0;
}
/*
Example
inputCopy
2
5
2 2 2 2 2
6
1 3 3 1 2 3
outputCopy
5
2
*/
然后我们发现,这个代码跑了1700ms,用了145000kb,大概是140mb,如果是128mb就要mle了,这时候我们可以压掉一个数组,把 \(suf\) 数组去掉,用类似前缀和的思想用大减小,这样就只有72000kb,也就是70mb。
Code:
/*
ID: Loxilante
Time: 2020/08/26
Prog: CF1400D
Lang: cpp
*/
#ifdef ONLINE_JUDGE
#pragma GCC optimize("O3")
#endif
#include <bits/extc++.h>
#define rep(i, l, r) for(int i = l; i < r; i++)
#define hrp(i, l, r) for(int i = l; i <= r; i++)
#define rev(i, r, l) for(int i = r; i >= l; i--)
#define ms(n, t) memset(n, t, sizeof(n))
#define pb push_back
#define int ll
#ifndef JOEON
#define D(...) 97
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
template<typename tn = int> inline tn next(void) { tn k; cin>>k; return k; }
const int U = 3e3+50;
int pr[U][U], w[U];
signed main(void)
{
clock_t Begin = clock();
#ifdef JOEON
// freopen("C:\\Users\\Joeon\\Desktop\\IN.txt", "r", stdin);
// freopen("C:\\Users\\Joeon\\Desktop\\OUT.txt", "w", stdout);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
int T = next();
clock_t InputFinished = clock();
while(T--)
{
int n = next(), ans = 0;
rep(i, 0, n) cin>>w[i];
ms(pr, 0);
rep(i, 0, n)
{
if (i) hrp(j, 0, n) pr[i][j] = pr[i-1][j];
pr[i][w[i]]++;
}
rep(j, 1, n-2) rep(k, j+1, n-1) ans += pr[j-1][w[k]]*(pr[n-1][w[j]]-pr[k][w[j]]);
cout<<ans<<endl;
}
clock_t End = clock();
D((double)(End-Begin)/CLOCKS_PER_SEC);
D((double)(End-InputFinished)/CLOCKS_PER_SEC);
return 0;
}
/*
Example
inputCopy
2
5
2 2 2 2 2
6
1 3 3 1 2 3
outputCopy
5
2
*/
E:
sharbee重题。
给定一个数列 \(w\),支持以下操作:
- 将\([l, r]\)中的元素自减\(1\).
- 将\(w_x\)的元素自减\(t\).
求最少的操作次数,使数列w变为\(0\)。
先看题目,仔细一瞧,满足大问题分解成小问题的性质,这时候有两种选择,一是分治,二是dp,我选择分治,因为dp感觉有点难(
然后考虑分治函数,把一个大序列分解成左,右两个小序列,然后分别求解。
最后设计函数参数,首先begin, end是必不可少哒,其次我还设置了一个height,表示父问题中最小的元素的值。
Code:
/*
ID: Loxilante
Time: 2019/10/07
Prog: CF1400E
Lang: cpp
*/
#ifdef ONLINE_JUDGE
#pragma GCC optimize("O3")
#endif
#include <bits/extc++.h>
#define rep(i, l, r) for(int i = l; i < r; i++)
#define hrp(i, l, r) for(int i = l; i <= r; i++)
#define rev(i, r, l) for(int i = r; i >= l; i--)
#define ms(n, t) memset(n, t, sizeof(n))
#define pb push_back
#define int ll
#ifndef JOEON
#define D(...) 97
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
template<typename tn = int> inline tn next(void) { tn k; cin>>k; return k; }
const int U = 5e3+50;
int w[U];
inline int solve(int begin, int end, int height) // [, )
{
if (begin >= end) return 0;
int mid = min_element(w+begin, w+end)-w, ans; // 找到最小元素然后分治
ans = min(end-begin, solve(begin, mid, w[mid])+solve(mid+1, end, w[mid])+w[mid]-height);
// end-begin表示把每个元素都清0的个数
return ans;
}
signed main(void)
{
clock_t Begin = clock();
#ifdef JOEON
// freopen("C:\\Users\\Joeon\\Desktop\\IN.txt", "r", stdin);
// freopen("C:\\Users\\Joeon\\Desktop\\OUT.txt", "w", stdout);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
int n = next();
rep(i, 0, n) cin>>w[i];
clock_t InputFinished = clock();
cout<<solve(0, n, 0)<<endl;
clock_t End = clock();
D((double)(End-Begin)/CLOCKS_PER_SEC);
D((double)(End-InputFinished)/CLOCKS_PER_SEC);
return 0;
}