链接:https://ac.nowcoder.com/acm/contest/6489/B
来源:牛客网
牛牛有一个长度为N的由小写字母组成的字符串S,还有一个整数K。在每一步中,牛牛都可以选择一个位置 i 并在 i 和 i + K 处交换字符(i + K < N)并且S_i < S_{i+k}S
i
<S
i+k
,即交换之后,新形成的字符串应字典序大于旧字符串。牛牛想尽可能交换尽量多的步数。他想知道最多可以交换多少
C++:
归并写法,排逆序,统计能够修改的次数
class Solution
{
public:
/**
*
* @param s string字符串 s.size() <= 1e5
* @param k int整型 k <= s.size()
* @return int整型
*/
int ans=0,a[100005],c[100005];
void sort_merge(int l,int r)
{
if(l<r)
{
int mid=(l+r)>>1,tmp=1;
sort_merge(l,mid);
sort_merge(mid+1,r);
int i=l,j=mid+1;
while(i<=mid&&j<=r)
{
if(a[i]<a[j])
{
c[tmp++]=a[j++];
ans+=mid-i+1;
}
else
{
c[tmp++]=a[i++];
}
}
while(i<=mid)
c[tmp++]=a[i++];
while(j<=r)
c[tmp++]=a[j++];
int m=1;
for(int i=l; i<=r; i++)
{
a[i]=c[m++];
}
}
}
int turn(string s, int k)
{
// write code here
for(int i=0; i<k; i++)
{
int tmp=0;
for(int j=i; j<s.size(); j+=k)
{
a[++tmp]=s[j]-'a';
}
sort_merge(1,tmp);
}
return ans;
}
};
暴力写法:直接分组模拟,然后统计能够交换的次数(后面的字母比前面的字母大的个数)
class Solution
{
public:
/**
*
* @param s string字符串 s.size() <= 1e5
* @param k int整型 k <= s.size()
* @return int整型
*/
int turn(string s, int k)
{
// write code here
int cnt[30];
int sum=0;
for(int i=0; i<k; i++)
{
memset(cnt,0,sizeof(cnt));
string x;
for(int j=i; j<s.size(); j+=k)
{
x+=s[j];
}
for(int j=0; j<x.size(); j++)
{
cnt[x[j]-'a']++;
for(int m=0;m<x[j]-'a';m++)
{
sum+=cnt[m];
}
}
}
return sum;
}
};
树状数组:
class Solution {
public:
int a[123456],tmp[123456],cnt=0;
int n,m;
int maxn = 123456;
int lowbit(int x){
return x&(-x);
}
void add(int x,int k){
for(int i=x;i<=maxn;i+=lowbit(i)){
a[i]+=k;
}
}
int query(int x){
int ans=0;
for(int i=x;i>0;i-=lowbit(i)){
ans+=a[i];
}
return ans;
}
void work(){
memset(a,0,sizeof(a));
for(int i=m;i>=1;i--){
add(tmp[i],1);
cnt+=query(tmp[i]-1);
}
}
int turn(string s, int k) {
// write code here
cnt=0;
reverse(s.begin(),s.end());
int len = s.size();
for(int i=0;i<k;i++){
m=0;
for(int j=i;j<len;j+=k){
tmp[++m]=(int)(s[j]-'a'+1);
}
work();
}
return cnt;
}
};