D. Constructing the Array
題目鏈接:點擊查看
題目描述:
給一個n個0的數組,每次都去尋找最左邊的最長連續0子段的中間位置進行賦值。
題目分析:
可以使用優先隊列進行解決,每次都是將node(l,r)添加進去,每次取出來的都是連續0長度最長或者是最左邊的段。
代碼:
#include<bits/stdc++.h>
using namespace std;
int n;
int a[200005];
struct node{
int l;
int r;
node(int x,int y){
l=x;
r=y;
}
bool operator < (const node & temp)const{
if(r-l==temp.r-temp.l){
return temp.l < l;//相等長度,左邊優先
}
return temp.r-temp.l>r-l;
}
};
priority_queue<node> q;
void bfs(){
int cnt=0;
q.push(node(1,n));
while(!q.empty()){
node temp = q.top();
q.pop();
if(temp.l>temp.r)continue;
int mid = (temp.l+temp.r)>>1;
a[mid]=++cnt;
q.push(node(temp.l,mid-1));
q.push(node(mid+1,temp.r));
}
}
int main()
{
int t;
cin >> t;
while(t--){
scanf("%d",&n);
bfs();
for(int i = 1; i <= n; ++i){
printf("%d ",a[i]);
}
cout << endl;
}
return 0;
}
E. K-periodic Garland
題目鏈接:點擊查看
題目描述:
給一個01字符串,每次操作改變一個字符狀態,使得字符串中1的相鄰距離爲k,問最少操作數。
題目分析:
可以使用dp進行解決。
sum[i]:記錄前i項中1的個數。
dp[i][0]表示前i項都正確,第i位爲0時的最小操作次數。
dp[i][1]表示前i項都正確,第i位爲1時的最小操作次數。
轉移方程:
- dp[i][0]=min(dp[i−1][0],dp[i−1][1])+(s[i]==‘1’)
當前記錄第i項爲0時的狀態,那麼此處爲0對前面是否正確不影響,可以直接
從dp[i−1][0]或者dp[i−1][1]轉移過來,如果s[i]==‘1’,那麼操作數加1。
- dp[i][1]=min(dp[i−k][1]+sum[i−1]−sum[i−k],sum[i−1])+(s[i]==‘0’)
當前記錄第i項爲1時的狀態,如果前i−k項合法時,要使第i項爲1時合法,需要我們使第i−k+1項到第i−1項都爲0,第i項才能爲1,這也就是爲什麼要記錄前綴和1的個數。或者讓前i-1項數都爲0,這種情況是sum[i-1]。然後比較取小值。最後操作數會根據s[i]=='0’繼續加1。
代碼:
#include<bits/stdc++.h>
using namespace std;
int n,k;
int sum[1000005];
char s[1000005];
int dp[1000005][2];
int main()
{
int t;
cin >> t;
while(t--){
cin >> n >> k; //scanf輸入,下面輸入字符串很難受
cin >> s+1;
for(int i = 1; i <= n; ++i){
sum[i]=sum[i-1]+(s[i]=='1');
}
int temp;
for(int i = 1; i <= n; ++i){
temp=max(0,i-k);//需要注意i-k
dp[i][0]=min(dp[i-1][0],dp[i-1][1])+(s[i]=='1');
dp[i][1]=min(dp[temp][1]+sum[i-1]-sum[temp],sum[i-1])
+(s[i]=='0');
}
cout << min(dp[n][0],dp[n][1]) << endl;
for(int i = 0; i <= n; ++i){
dp[i][0]=0,dp[i][1]=0,sum[i]=0;//別忘了初始化
}
}
return 0;
}