CF-div2-630-C - K-Complete Word


思路

1.與當前i相關聯的有 i,i+k,i+2k n-i+1, n-i+1-k,n-i+1-2k... ,題目就是讓我們把這些位置上的字符變成一樣,花費的最小值
2.考慮當前這個數a[i]的局部最優解,如何花費最小,貪心的想,肯定是把與它關聯的 i,i+k,i+2k n-i+1, n-i+1-k... 這些字符改成這些字符串現次數最多的字符,(改成原次數出現最多的字符,就代表“這一輪一共修改的最少”),
3.考慮貪心有沒有bug,(2)中局部求最優解,但這樣貪心並不一定整體就最優,想一想這樣局部求最優是否有無后效性。即當前選擇的結果必須不能對之前的結果狀態產生影響!
考慮i從1~n 肯定會出現判重復,對重復的數相關聯的數再去修改就不能達到最優了!
想到可以設置標記數組,來標記之前是否修改過,因為前面修改過的數肯定是用和它相關聯的數來修改的,已經 把與他相關聯的 做了修正 這次就不用考慮他了,也不用再考慮與它相關聯的數了。

代碼

#include<bits/stdc++.h>
using namespace std;

int t,n,k,ans;
const int maxn = 2e5+100;
bool vis[maxn];
char s[maxn]; 
int cnt[30];

void init(){
	ans = 0;
	for(int i=1;i<=n;i++) vis[i] = false;
}

void solve(){
	cin>>n>>k;
	scanf("%s",s+1);
	init();
	for(int i=1;i<=n;i++){
		if(vis[i]) continue;
		for(int j=0;j<27;j++) cnt[j] = 0;
		int cnt1 = 0;
		int mx = 0;
		//與當前i相關聯的有 i,i+k,i+2k  n-i+1, n-i+1-k... 
		//考慮從1~n判 肯定會出現判重復 設置vis數組標記用過 
		//因為前面用過的數肯定已經 把與他相關聯的 做了修正 這次就不用考慮他了 
		for(int j=i;j<=n;j+=k){ //k個一組 
			if(!vis[j]){  //防止重復計算 
				vis[j] = true;
				cnt1++;
				cnt[s[j] - 'a']++;
				mx = max(cnt[s[j] - 'a'],mx);
			}else break;  
		}
		for(int j=n-i+1;j>=1;j-=k){ //i對應的回文(另一端) k個一組 
			if(!vis[j]){
				vis[j] = true;
				cnt1++;
				cnt[s[j] - 'a']++;
				mx = max(cnt[s[j] - 'a'],mx);
			}else break;
		}
		ans += cnt1 - mx;
	}
	cout<<ans<<endl;
}

int main(){
	cin>>t;
	while(t--){
		solve();
	}
	return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM