1. 程式人生 > >Problem 5. Decimal Array Expansion 2018 Goldman Sachs Women's CodeSprint

Problem 5. Decimal Array Expansion 2018 Goldman Sachs Women's CodeSprint

題意:輸入一個由0-9組成的字串A,給定一組轉換規則S,S[i]把數字i map到一個新的string,如此可將A一層一層擴充套件,直到長度>=M為止,給定一組query,求擴充套件後的字串的區間和。

這一題其實也沒那麼難,但是標了個hard,讓人不戰而敗。。感覺自己還是不夠confident + aggressive ε=(´ο`*)))唉

擴充套件的過程類似於生成一棵樹,第一層節點是A,然後每個節點逐層擴充套件。一個observation是因為相同數字擴充套件規則相同,所以如果A[i]=A[j],那麼擴充套件後A[i]和A[j]對應的子樹是一樣的。同理,同一層相同的節點擴充套件後的子樹也是一樣得。

求區間和等價於求字首和,求[0,...,l]的字首和,需要每個子樹所擁有的葉子個數,以及對應的葉子value之和。

因為每一層不同的節點最多隻有10個,所以用fnum[10][maxk]記錄葉子個數,fnum[i][k]表示第k層數字i對應的子樹葉子節點個數。另外,用fsum[10][maxk]記錄葉子value之和,fsum[i][k]表示第k層數字i對應的子樹葉子節點value之和。

fnum[i][k]和fsum[i][k]可以用樹dp(記憶化搜尋)求得,樹是遞迴結構,感覺很多問題都是遞迴求解。fnum[i][k]=sum_j fnum[j][k+1],fsum[i][k]=sum_j fsum[j][k+1], j is the number expanted from i。遞迴出口是在最大層(葉子層)時,fnum[i][k]=1,fsum[i][k]=i。

求字首和類似於線段樹從頂端往下搜尋,先對於fnum[A[i]][0]進行二分查詢,找出第0層l應該在那一個子樹中,如果在第i個子樹中,返回presum of fsum[0,...,i-1]+dfs(l-presum of fnum[0,...,i-1])。對於子樹中的每個node,也是找到第一個child使得其fnum[i][k]字首和剛好>l,再從該child對應的子樹中搜索,傳入的引數l應該減去child之前的子樹葉子節點數之和。遞迴出口是最大層是返回1,此時找到了對應的l,也恰巧l=1。

開始WA是因為理解錯了題意,以為S[i]長度都一樣。。結束後可以看test case。。然後發現咦居然還有這種input。。

給定M,求最大層數maxlvel也可以由逐層擴充套件模擬實現。第k層記錄0-9出現的頻次,然後k+1層可以根據拓展規則S求出第k層的數字i會生成0-9的數字頻次是多少,之後相加即可。

#include<iostream>
#include<stdio.h>
#include<cstdio>
#include<string>
#include<cmath>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
#include<cstring>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
#include<list>
using namespace std;


const int maxn=20;
int T;
int N;
int M;
int Q;
vector<long>presum;
vector<long>presumsum;
string Ag;
vector<string>dict;
int L;
int R;
const int maxk=1000;//max level of tree
long fnum[maxn][maxk];
long fsum[maxn][maxk];
bool vis[maxn][maxk];
int maxlevel;

long calc_sum_leaf(int num,int k)
{
    if(vis[num][k]==true)
    {
        return fsum[num][k];
    }
    if(k==maxlevel)
    {
        fsum[num][k]=num;
        vis[num][k]=true;
        return num;
    }
    else
    {
        long childsum=0;
        for(int i=0;i<dict[num].length();i++)
        {
            childsum+=calc_sum_leaf(dict[num][i]-'0',k+1);
        }
        fsum[num][k]=childsum;
        vis[num][k]=true;
        return fsum[num][k];
    }
}

long calc_leaf_num(int num,int k)
{
    if(vis[num][k]==true)
    {
        return fnum[num][k];
    }
    if(k==maxlevel)
    {
        fnum[num][k]=1;
        vis[num][k]=true;
//        cout<<"num "<<num<<" level "<<k<<" "<<fnum[num][k]<<endl;
        return 1;
    }
    else
    {
        long childnum=0;
        for(int i=0;i<dict[num].length();i++)
        {
            childnum+=calc_leaf_num(dict[num][i]-'0',k+1);
        }
        fnum[num][k]=childnum;
        vis[num][k]=true;
//        cout<<"num "<<num<<" level "<<k<<" "<<fnum[num][k]<<endl;
        return fnum[num][k];
    }
}

void initialize(int n, long m, string A, vector<string> S) {
//    m=1e17;
//    cout<<m<<endl;
    dict.clear();
    presum.clear();
    presumsum.clear();
    for(int i=0;i<S.size();i++)
    {
        dict.push_back(S[i]);
    }
    Ag=A;
    long long cnt=n;
    long numfreq[2][maxn];//rolling, one is current, one is next
    long currnumfreq[maxn][maxn];//[i,j] num i will leads xxx # of j to appear in the expansion
    memset(numfreq,0,sizeof(numfreq));
    memset(currnumfreq,0,sizeof(currnumfreq));
    for(int i=0;i<10;i++)
    {
//        cout<<"num "<<i<<endl;
        for(int j=0;j<dict[i].size();j++)
        {
            currnumfreq[i][dict[i][j]-'0']++;
        }
//        for(int j=0;j<10;j++)
//        {
//            cout<<currnumfreq[i][j]<<" ";
//        }
//        cout<<endl;
    }

    int curr=0;
    for(int i=0;i<A.length();i++)
    {
        numfreq[curr][A[i]-'0']++;
    }
    cnt=A.length();
    for(int i=0;i<maxk;i++)
    {
//        cout<<"level "<<i<<" cnt "<<cnt<<endl;
        if(cnt>=m)
        {
            maxlevel=i;
            break;
        }
        cnt=0;
        int nextcurr=(curr+1)%2;
        memset(numfreq[nextcurr],0,sizeof(numfreq[nextcurr]));
        for(int j=0;j<10;j++)
        {
//            cout<<"num "<<j<<" "<<numfreq[curr][j]<<endl;
            if(numfreq[curr][j]==0)
            {
                continue;
            }
            else
            {
                for(int k=0;k<10;k++)
                {
                    numfreq[nextcurr][k]+=numfreq[curr][j]*currnumfreq[j][k];
//                    cout<<"Add "<<k<<" count "<<numfreq[curr][j]*currnumfreq[j][k]<<endl;
                }
            }

        }
        for(int j=0;j<10;j++)
        {
            cnt+=numfreq[nextcurr][j];
        }
        curr=nextcurr;
    }
//    long expand=S[0].length();//different S[i] may have different length
//    for(int i=0;i<maxk;i++)
//    {
////        cout<<i<<" "<<cnt<<endl;
//        if(cnt>=m)
//        {
//            maxlevel=i;
//            break;
//        }
//        cnt*=expand;
//    }
    //maxlevel=60;
    cout<<"max level "<<maxlevel<<endl;
    memset(fnum,0,sizeof(fnum));
    memset(fsum,0,sizeof(fsum));
    memset(vis,false,sizeof(vis));
    for(int i=0;i<A.length();i++)
    {
        calc_sum_leaf(A[i]-'0',0);
    }
//    cout<<"here0"<<endl;
//    for(int j=0;j<=maxlevel;j++)
//    {
//        for(int i=0;i<10;i++)
//        {
//            cout<<"num "<<i<<" level "<<j<<" "<<fsum[i][j]<<" "<<endl;
//        }
//        cout<<endl;
//    }

    memset(vis,false,sizeof(vis));
    for(int i=0;i<A.length();i++)
    {
//        cout<<"calc num of "<<A[i]<<endl;
        calc_leaf_num(A[i]-'0',0);
    }
//    cout<<"here1"<<endl;
//    for(int j=0;j<=maxlevel;j++)
//    {
//        for(int i=0;i<10;i++)
//        {
//            cout<<"num "<<i<<" level "<<j<<" "<<fnum[i][j]<<" "<<endl;
//        }
//        cout<<endl;
//    }

    //presum of node in the level 0
    presum.push_back(fnum[A[0]-'0'][0]);
    presumsum.push_back(fsum[A[0]-'0'][0]);
    for(int i=1;i<A.length();i++)
    {
        presum.push_back(presum[i-1]+fnum[A[i]-'0'][0]);
        presumsum.push_back(presumsum[i-1]+fsum[A[i]-'0'][0]);
    }
//    cout<<"presum"<<endl;
//    for(int i=0;i<presum.size();i++)
//    {
//        cout<<presum[i]<<" ";
//    }
//    cout<<endl;
//    cout<<"here2"<<endl;
//    for(int i=0;i<presumsum.size();i++)
//    {
//        cout<<presumsum[i]<<" ";
//    }
//    cout<<endl;

}
long dfs(long idx,int num,int k)
{
//    cout<<idx<<" "<<num<<" "<<k<<endl;
    if(k==maxlevel)
    {
        return (long)num;
    }
    long ret=0;
    for(int i=0;i<dict[num].size();i++)
    {
        int next=dict[num][i]-'0';
        if(fnum[next][k+1]<idx)
        {
            ret+=fsum[next][k+1];
            idx-=fnum[next][k+1];
        }
        else
        {
            ret+=dfs(idx,next,k+1);
            break;
        }
    }
    return ret;
}
long getpresum(long idx)
{
    if(idx==0)
    {
        return 0;
    }
//    cout<<"search idx "<<idx<<endl;
    int st=lower_bound(presum.begin(),presum.end(),idx)-presum.begin();
//    cout<<"start from "<<st<<endl;
    if(st==0)
    {
        return dfs(idx,Ag[st]-'0',0);
    }
    //start from sub tree in level 0;
    else
    {
//        cout<<"pre sub tree "<<fsum[Ag[st-1]-'0'][0]<<endl;
        return presumsum[st-1]+dfs(idx-presum[st-1],Ag[st]-'0',0);
    }

}

long query(long l, long r) {
    return getpresum(r)-getpresum(l-1);
}

int main()
{
//    list<char>arr;
//    for(int i=0;i<5;i++)
//    {
//        arr.push_back(i+'0');
//    }
//    for(list<int>::iterator iter=arr.begin();iter!=arr.end();)
//    {
//        if((*iter)==2)
//        {
//            iter=arr.erase(iter);
//            cout<<(*iter)<<endl;
//            break;
//        }
//        else
//        {
//            iter++;
//        }
////        arr.insert(iter,10);
//
//    }
//    for(list<int>::iterator iter=arr.begin();iter!=arr.end();iter++)
//    {
//        cout<<(*iter)<<" ";
//    }
//    cout<<endl;
//    return 0;
    freopen("input.txt","r",stdin);
//    freopen("out.txt","w",stdout);
//    freopen("out-cmp.txt","w",stdout);
    cin>>T;
    for(int ca=1;ca<=T;ca++)
    {
        cin>>N>>M>>Q;
        string A;
        vector<string>S;
        cin>>A;
        cin.ignore();
        S.clear();
//        cout<<N<<" "<<M<<" "<<Q<<endl;
        for(int i=0;i<10;i++)
        {
            string tmp;
            cin>>tmp;
            cin.ignore();
//            cout<<"tmp "<<tmp<<"ed"<<endl;
            S.push_back(tmp);
        }
//        cin.ignore();
        initialize(N,M,A,S);
        for(int i=0;i<Q;i++)
        {
            cin>>L>>R;
//            cout<<L<<" "<<R<<endl;
            cout<<query(L,R)<<endl;
//            cout<<"presum of R "<<R<<" "<<getpresum(R)<<endl;
        }

//        cout<<"Case #"<<ca<<": "<<query(L,R)<<endl;

    }
    return 0;
}

附上最初認慫用linked list暴力模擬的程式碼。。

#include<iostream>
#include<stdio.h>
#include<cstdio>
#include<string>
#include<cmath>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
#include<cstring>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
#include<list>
using namespace std;


const int maxn=10;
int T;
int N;
int M;
int Q;
vector<long>presum;
string A;
vector<string>S;
int L;
int R;
const int maxk=60;//max level of tree

void initialize(int n, long m, string A, vector<string> S) {
    presum.clear();
//    cout<<"A "<<A<<endl;
//    for(int i=0;i<S.size();i++)
//    {
//        cout<<S[i]<<endl;
//    }
//    cout<<"end input"<<endl;
//    vector<char>arr;
    list<int>arr;
    for(int i=0;i<n;i++)
    {
        arr.push_back(A[i]-'0');
    }
//    cout<<"here"<<endl;
    int cnt=n;
    while(cnt<m)
    {
        for(list<int>::iterator iter=arr.begin();iter!=arr.end();)
        {
            int tmp=*iter;
//            cout<<tmp<<endl;
            iter=arr.erase(iter);
//            cout<<"after erase "<<(*iter)<<endl;
//            arr.insert(iter,9);
            for(int i=0;i<S[tmp].length();i++)
            {
                arr.insert(iter,S[tmp][i]-'0');
//                cout<<"insert "<<S[tmp][i]<<endl;
            }
            cnt+=S[tmp].length()-1;
        }
    }
//    for(list<int>::iterator iter=arr.begin();iter!=arr.end();iter++)
//    {
//        cout<<(*iter)<<" ";
//    }
//    cout<<endl;
    list<int>::iterator iter=arr.begin();
    presum.push_back(0);
    for(int i=1;i<=cnt;i++)
    {
//        presum[i]=(*iter)+presum[i-1];
        presum.push_back((*iter)+presum[i-1]);
        iter++;
    }
//    for(int i=0;i<=cnt;i++)
//    {
//        cout<<presum[i]<<" ";
//    }
//    cout<<endl;
}

long query(long l, long r) {
//    cout<<r<<" "<<l-1<<" "<<presum[r]<<" "<<presum[l-1]<<endl;
//    for(int i=0;i<=M;i++)
//    {
//        cout<<presum[i]<<" ";
//    }
//    cout<<endl;
    return presum[r]-presum[l-1];
}
int main()
{
//    list<char>arr;
//    for(int i=0;i<5;i++)
//    {
//        arr.push_back(i+'0');
//    }
//    for(list<int>::iterator iter=arr.begin();iter!=arr.end();)
//    {
//        if((*iter)==2)
//        {
//            iter=arr.erase(iter);
//            cout<<(*iter)<<endl;
//            break;
//        }
//        else
//        {
//            iter++;
//        }
////        arr.insert(iter,10);
//
//    }
//    for(list<int>::iterator iter=arr.begin();iter!=arr.end();iter++)
//    {
//        cout<<(*iter)<<" ";
//    }
//    cout<<endl;
//    return 0;
    freopen("input.txt","r",stdin);
//    freopen("out.txt","w",stdout);
//    freopen("out-cmp.txt","w",stdout);
    cin>>T;
    for(int ca=1;ca<=T;ca++)
    {
        cin>>N>>M>>Q;
        cin>>A;
        cin.ignore();
        S.clear();
//        cout<<N<<" "<<M<<" "<<Q<<endl;
        for(int i=0;i<10;i++)
        {
            string tmp;
            cin>>tmp;
            cin.ignore();
//            cout<<"tmp "<<tmp<<"ed"<<endl;
            S.push_back(tmp);
        }
//        cin.ignore();
        initialize(N,M,A,S);
        for(int i=0;i<Q;i++)
        {
            cin>>L>>R;
//            cout<<L<<" "<<R<<endl;
            cout<<query(L,R)<<endl;
        }

        cout<<"Case #"<<ca<<": "<<query(L,R)<<endl;

    }
    return 0;
}