Topcoder SRM 648 Div2 1000

Topcoder SRM 648 Div2 1000
Problem
  给一个长度为N的字符串S,S只含有‘A’、'B'、'C'三种元素。给定一个K,要求返回字符串S,使得S中恰好有K对pair(i,j)满足 0=<i<j<N,且 S[i]<S[j]。若不存在,则返回空串。

Limits
Time Limit(ms): 2000
Memory Limit(MB): 256
N: [3, 30]
K: [0, N*(N-1)/2 ]

Solution
  设S中含有n1个‘A’,n2个‘B’,n3个'C',设num=n1*n2+n1*n3+n2*n3,num即为S中pair的总数;先O(N^3)求出n1,n2,n3以及num 使得n1+n2+n3=N 且 num最大。若K>num,则不存在;否则一定存在,用插空法求出即可。

More
  简单阐述如何用插空法求S。先假设S含有n1个'A',然后将n2个'B'适当插入S,再将n3个'C'适当插入S。
  关于插空法的具体做法以及为何 ”K>num则不存在“,请看上篇文章,Div1 250与Div2 1000方法一致。

Complexity
Time Complexity: O(N^3)
Memory Complexity: O(N)

Source
Topcoder SRM 648 Div2 1000

Code
Topcoder SRM 648 Div2 1000 From My Github

代码如下:
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
using namespace std;
class ABC{
public:
    int num[40];
    bool isA[40];
    string createString(int n, int k){
        int n1=0,n2=0,n3=0,nt=-1;
        for(int i1=0;i1<n;i1++){
            for(int i2=0;i2<n;i2++){
                for(int i3=0;i3<n;i3++){
                    if(i1+i2+i3==n){
                        if(i1*i2+i1*i3+i2*i3>nt){
                            nt=i1*i2+i1*i3+i2*i3;
                            n1=i1,n2=i2,n3=i3;
                        }
                    }
                }
            }
        }
        if(k>nt) return "";//判断无解
        //先往“AAA..”中插入'B'
        string s; s.clear();
        memset(num,0,sizeof(num));
        nt=n2;
        while(k && nt){
            int kt=min(n1,k);
            num[kt]+=1;
            k-=kt;
            nt-=1;
        }
        for(int i=0;i<nt;i++){
            s+="B";
        }
        for(int i=1;i<=n1;i++){
            s+="A";
            while(num[i]--){
                s+="B";
            }
        }
        for(int i=0;i<n1+n2;i++){
            isA[i]=s[i]=='A'?true:false;
        }
        //再插入'C'
        memset(num,0,sizeof(num));
        nt=n3;
        while(k && nt){
            int kt=min(n1+n2,k);
            num[kt]+=1;
            k-=kt;
            nt-=1;
        }
        s.clear();
        for(int i=0;i<nt;i++){
            s+="C";
        }
        for(int i=1;i<=n1+n2;i++){
            s+=isA[i-1]?"A":"B";
            while(num[i]--){
                s+="C";
            }
        }
        return s;
    }
};

你可能感兴趣的:(数学,插空法)