zoukankan      html  css  js  c++  java
  • 密码

    https://zybuluo.com/ysner/note/1176102

    题面

    给定一字符串(S),现可进行(M)次交换相邻字符的操作,询问操作完后可能的最小字典序的字符串。

    • (60pts) (len_Sleq3000)
    • (100pts) (len_Sleq10^5,Mleq(len_S-8)^2+2)

    解析

    (len_Sleq3000)

    显然从前往后枚举字符,暴力把可能的最小字符移到当前位置即可。
    最坏复杂度(O(n^2)),期望(60pts)
    但复杂度不太满,如数据过水可获得(80-90pts)

    scanf("%lld",&n);
      scanf("%s",a+1);len=strlen(a+1);
      fp(i,1,len)
        {
          re ll s=min(i+n,len),pos=i;char zsy=a[i];
          fp(j,i,s)
    	if(a[j]<zsy||(a[j]==zsy&&j<pos)) zsy=a[j],pos=j;
          n-=(pos-i);
          zsy=a[pos];fq(j,pos,i+1) a[j]=a[j-1];a[i]=zsy;
          if(!n) break;
        }
      printf("%s
    ",a+1);
    

    (len_Sleq10^5)

    发现寻找可行域内最小字符很耗时间。
    我们可以用树状数组维护每个字符前需要交换的字符数,用链表维护(26)个字符出现的第一个位置。
    关键在于交换字符后,我们不关心字符间的顺序,只关心字符个数。
    交换完后把本在后面的字符删掉即可。

    #include<iostream>
    #include<cmath>
    #include<cstring>
    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #define ll long long
    #define re register
    #define il inline
    #define min(a,b) ((a)<(b)?(a):(b))
    #define fp(i,a,b) for(re int i=a;i<=b;i++)
    #define fq(i,a,b) for(re int i=a;i>=b;i--)
    using namespace std;
    const int N=2e5;
    ll n,len,h[N],nxt[N],t[N];
    char a[N];
    il void add(re ll x,re ll w){for(;x<=len;x+=x&-x) t[x]+=w;}
    il ll Query(re ll x){re ll ans=0;for(;x;x-=x&-x) ans+=t[x];return ans;}
    int main()
    {
      freopen("pasuwado.in","r",stdin);
      freopen("pasuwado.out","w",stdout);
      scanf("%lld",&n);
      scanf("%s",a+1);len=strlen(a+1);
      fq(i,len,1) nxt[i]=h[a[i]-96],h[a[i]-96]=i;//为26个字母按从前往后顺序分别建立位置链表,原先的h移到next
      fp(i,1,len) add(i,1);
      fp(i,1,len)
        {
          fp(j,1,26)
    	{
    	  re int pos=h[j];
    	  if(!pos) continue;
    	  re int sum=Query(pos-1);
    	  if(n>=sum)
    	    {
    	      n-=sum;
    	      add(pos,-1);
    	      h[j]=nxt[pos];//改变移完的字符的第一位
    	      printf("%c",j+96);
    	      break;
    	    }
    	}
        }
      puts("");
      fclose(stdin);
      fclose(stdout);
      return 0;
    }
    
  • 相关阅读:
    linux 命令——19 find (转)
    linux 命令——18 locate (转)
    linux 命令——17 whereis(转)
    linux 命令——16 which(转)
    linux 命令——15 tail (转)
    linux 命令——14 head (转)
    Java for LeetCode 038 Count and Say
    Java for LeetCode 037 Sudoku Solver
    Java for LeetCode 036 Valid Sudoku
    Java for LeetCode 035 Search Insert Position
  • 原文地址:https://www.cnblogs.com/yanshannan/p/9157363.html
Copyright © 2011-2022 走看看