22分钟A了前三题,然后…然后就没然后了,这里补下DE题
D题解题思路:
- 这个题开始就是找规律…找…
- 正解是set或者优先队列,这里用优先队列写下
- 首先我们是从哪个区间大我们就往哪个区间的中间位置放数,所以我们就存储他的头和尾的坐标,一开始肯定是1,n
- 我们这里对优先队列排序,按照长度由长到短,如果长度相同那么看坐标小就排在前面(这里学了下优先队列的排序,与sort是反的)
struct cmp{
bool operator()(PII x, PII y){
if (x.second - x.first == y.second - y.first){
return x.first > y.first;
}
else{
return x.second - x.first < y.second - y.first;
}
}
};
priority_queue<PII,vector<PII>,cmp> q;
- 然后我们对这个区间进行分解,按照中间位置分为左右2部分,然后首尾坐标push进队列
- 然后如果首尾坐标相同,结束后就不用push进队列了
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
typedef pair<int,int> PII;
const int N = 200010;
int a[N];
struct cmp{
bool operator()(PII x, PII y){
if (x.second - x.first == y.second - y.first){
return x.first > y.first;
}
else{
return x.second - x.first < y.second - y.first;
}
}
};
int main(){
int t;
scanf("%d",&t);
while(t--){
priority_queue<PII,vector<PII>,cmp> q;
int n;
scanf("%d",&n);
q.push({1,n});
int cnt = 0;
while(!q.empty()){
cnt ++;
PII t = q.top();
q.pop();
if (t.first == t.second){
a[t.first] = cnt;
}
else if((t.second - t.first + 1) % 2 == 1){
int x = (t.second + t.first) / 2;
a[x] = cnt;
if (x - 1 >= t.first) q.push({t.first,x - 1});
if (x + 1 <= t.second)q.push({x + 1,t.second});
}
else{
int x = (t.second + t.first - 1) / 2;
a[x] = cnt;
if (x - 1 >= t.first) q.push({t.first,x - 1});
if (x + 1 <= t.second)q.push({x + 1,t.second});
}
}
for (int i = 1; i <= n; i++){
printf("%d ",a[i]);
}
puts("");
}
return 0;
}
E题解题思路:
- dp,不过自己也不会写,因为想不太明白状态
- 首先,如果没有0或者有1个0,那么肯定输出 0
- 然后我们考虑别的情况,情况分为2种,第一种是当前位置是开头,第二种是该位置不是开头(那么i >= k)
- 第一种是开头的话,那么好考虑,让前面的值都变成0,然后当前位如果是0就需要变成1,如果是1就不需要变
dp[i] = a[i - 1] + (b[i] == 0);
- 第二种情况就是i >= k,那么不是第一个点,前面肯定还有一个点,所以我们是从dp[i - k]转移过来的,这其中要将他们之间的1变为0,a[i - 1] - a[i -k + 1],然后需要把当前位变为1(如果原本是0的话,那么就不用换)
dp[i] = min(dp[i],(b[i] == 0) + dp[i - k] + a[i - 1] - a[i - k]);
- 最后我们遍历,如果当前的位置是最后一个位置,那么后面的都要变成0
for (int i = 1; i <= n; i++){
res = min(res,dp[i] + a[n] - a[i]);
}
- 最后这里比较坑的是不要memset(超时超死我了)
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
const int N = 1000010;
int a[N], b[N], dp[N];
char st[N];
int main(){
int t;
scanf("%d",&t);
while(t--){
int n, k;
scanf("%d%d",&n,&k);
scanf("%s",st);
for (int i = 0; i <= n; i++) {
dp[i] = 0;
a[i] = 0;
b[i] = 0;
}
for (int i = 0; i < n; i++){
if (st[i] == '0'){
a[i + 1] = 0;
}
else{
a[i + 1] = 1;
}
b[i + 1] = a[i + 1];
a[i + 1] += a[i];
}
if (a[n] == 0 || a[n] == 1){
puts("0");
continue;
}
int res = 1e9;
for (int i = 1; i <= n; i++){
dp[i] = a[i - 1] + (b[i] == 0);
if (i - k >= 0) dp[i] = min(dp[i],(b[i] == 0) + dp[i - k] + a[i - 1] - a[i - k]);
}
for (int i = 1; i <= n; i++){
res = min(res,dp[i] + a[n] - a[i]);
}
printf("%d\n",res);
}
}