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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
import decimal def calculate_pi(): decimal.getcontext().prec = 35 pi = decimal.Decimal() k = while True: term = decimal.Decimal((-1) ** k) * (decimal.Decimal(2) ** (decimal.Decimal(5) * decimal.Decimal(k))) / (decimal.Decimal(4 * k + 1) * decimal.Decimal(math.factorial(k)) ** 2 * decimal.Decimal(396 ** (4 * k))) pi += term if abs(term) < decimal.Decimal(1e-35): break k += 1 return pi * decimal.Decimal(2 ** 6) def calculate_tan(x): decimal.getcontext().prec = 35 tan = decimal.Decimal() k = while True: term = decimal.Decimal((-1) ** k) * decimal.Decimal(2 ** (2 * k + 1)) * decimal.Decimal((2 ** (2 * k + 1) - 1)) * decimal.Decimal(x ** (2 * k + 1)) / decimal.Decimal(math.factorial(2 * k + 1)) tan += term if abs(term) < decimal.Decimal(1e-35): break k += 1 return tan def calculate_pi_with_tan(): decimal.getcontext().prec = 35 pi = decimal.Decimal() k = while True: term = decimal.Decimal((-1) ** k) * (decimal.Decimal(2) ** (decimal.Decimal(5) * decimal.Decimal(k))) / (decimal.Decimal(4 * k + 1) * decimal.Decimal(math.factorial(k)) ** 2 * decimal.Decimal(396 ** (4 * k))) * calculate_tan(decimal.Decimal(1) / decimal.Decimal(239)) pi += term if abs(term) < decimal.Decimal(1e-35): break k += 1 return pi * decimal.Decimal(2 ** 6) def kahan_sum(numbers): decimal.getcontext().prec = 35 sum = decimal.Decimal() c = decimal.Decimal() for number in numbers: y = number - c t = sum + y c = (t - sum) - y sum = t return sum pi = calculate_pi_with_tan() pi = kahan_sum([pi] * 10) print(pi) 这段代码有一些缺漏,请补充以便它计算出pi的值
03-10
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值