Educational Codeforces Round 165 (Rated for Div. 2) (A~C)
前言
完全小瞧了edu的难度,感觉较上一场div2难多了
A. Two Friends (签到)
如果两个人互相是好友,那只用发两人,否则发三个人
void solve(){
cin >> n;
map<pair<int ,int> ,int> mp;
for(int i = 1, x; i <= n; i++){
cin >> x;
mp[{x, i}]++;
mp[{i, x}]++;
}
for(auto [a, b] : mp){
if(b == 2){
cout << 2 << endl;
return;
}
}
cout << 3 << endl;
}
B. Shifts and Sorting (签到)
题意是循环右移任意区间,使最后形成\(0-1\)的序列,费用是区间长度,求最小费用
观察样例可知一次移动多个\(0\)不如一个一个移动费用小,因为每多一个\(0,1\)就要多移动\(1\)步,比如\(100\),如果\(3\)格移,要移两次,花\(6\)费,而\(2\)格移动,同样是两次花\(4\)费,
所以模拟这个过程就行
void solve(){
string s;
int pre = 0;
cin >> s;
n = s.length();
s = " " + s;
int ans = 0;
for(int i = 1; i <= n; i++){
if(s[i] == '0'){
if(i - pre > 1) // 如果和前个0相邻不用移动
ans += (i - pre);
pre++;
}
}
cout << ans << endl;
}
C. Minimizing the Sum (dp)
题意是给你一个数组,你可以执行以下操作:从数组中选择一个元素,并用其邻近元素的值替换它,最多执行\(k\)次。计算数组的最小总和。
这边的做法略显麻烦,感觉不太像正解:
观察得到 \(k < 10\),考虑 \(dp[n][k]\)符合复杂度,那么\(dp[i][j]\)状态显然是到第\(i\)个元素为止,进行k次操作最多能使总和减少多少。(直接记录答案应该也行)
当遍历到\(i,j\)的时候,记之前已经进行了多少次操作,设为\(last\),得到这一位的影响是是将前方最多\(pre\),\((pre <= j - last)\)个元素变成\(a_i\),后方最多 \((j - last - pre)\)个元素变成\(a_i\)。
那么转移方程就得到了\(dp[i + j - last - pre][j] = max(dp[i + j - last - pre][j], dp[i - pre - 1][last] + l[i][pre] + r[i][j - last - pre])\)
预处理\(l[i][j]\)表示将前面\(j\)个元素全都变成\(a_i\)导致的总和减少量。\(r[i][j]\)同理。
细节看代码
const int N = 3e5 + 9, inf = 0x3f3f3f3f;
int n, m, k;
int dp[N][11];
int a[N];
int l[N][11], r[N][11];
void solve(){
cin >> n >> k;
int sum = 0;
for(int i = 1; i <= n; i++){
cin >> a[i];
sum += a[i];
}
for(int i = 1; i <= n; i++){ //初始化
for(int j = 0; j <= 10; j++){
dp[i][j] = 0;
}
}
for(int i = 1; i <= n; i++){ //预处理
l[i][0] = 0;
for(int j = 1; j <= 10; j++){
if(i - j >= 1)
l[i][j] = l[i][j - 1] + (a[i - j] - a[i]);
if(i + j <= n)
r[i][j] = r[i][j - 1] + (a[i + j] - a[i]);
}
}
for(int i = 1; i <= n; i++){
for(int j = 0; j <= 10; j++){ //当然可以从i-1,j转移过来
dp[i][j] = max(dp[i - 1][j], dp[i][j]);
}
for(int j = 0; j <= 10; j++){
for(int last = 0; last <= j; last ++){
for(int pre = 0; pre <= j - last; pre++){
if(i - pre - 1 >= 0 && j - pre >= 0 && i + j - last - pre <= n && i - pre >= 1) //边界处理
dp[i + j - last - pre][j] = max(dp[i + j - last - pre][j], dp[i - pre - 1][last] + l[i][pre] + r[i][j - last - pre]);
}
}
}
}
int minn = 0;
for(int i = 0; i <= k; i++){
minn = max(minn, dp[n][i]);
}
cout << sum - minn << endl;
}

浙公网安备 33010602011771号