Google apac 在线笔试round2

笔试地址

这周做了下google的在线笔试第二轮,总结一下。

A题:
题目大意:给一个无向图,图中的边的权值会每小时变化一次,一天变化24次,然后给你k个询问,每个询问给你两个数D和S,问你在S时刻从节点1到节点D的最短路距离。

思路:第一题还是比较简单,直接建图跑最短路即可,因为每次都是从节点1出发,所以可以只做24次最短路,将每个时刻从1节点到其他的节点的最短距离算出来记录一下即可。

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <queue>
#define inf 2100000000
using namespace std;
int dist[510][24];
int cost[2010][24];
int ans[510][24];
struct edge{
    int to,next,id;
}e[4010];
int box[510],cnt;
void init(){
    memset(box,-1,sizeof(box));
    cnt=0;
}
void add(int from,int to,int id){
    e[cnt].to=to;
    e[cnt].id=id;
    e[cnt].next=box[from];
    box[from]=cnt++;
}
struct node{
    int u,t;
    node(){
    }
    node(int a,int b){
        u=a,t=b;
    }
};
int vis[510][24];
void spfa(int time,int n){
    for(int i=0;i<=n;i++){
        for(int j=0;j<24;j++){
            dist[i][j]=inf;
        }
    }
    queue<node> q;
    dist[1][time]=0;
    memset(vis,0,sizeof(vis));
    q.push(node(1,time));
    vis[1][time]=1;
    while(!q.empty()){
        node now=q.front();q.pop();
        int u=now.u,Time=now.t;
        vis[u][Time]=0;
        for(int t=box[u];t+1;t=e[t].next){
            int v=e[t].to,id=e[t].id;
            int nextt=(Time+cost[id][Time])%24;
            if(dist[v][nextt]>dist[u][Time]+cost[id][Time]){
                dist[v][nextt]=dist[u][Time]+cost[id][Time];
                if(!vis[v][nextt]){
                    vis[v][nextt]=1;
                    q.push(node(v,nextt));
                }
            }
        }
    }
    for(int i=1;i<=n;i++){
        int mi=inf;
        for(int j=0;j<24;j++){
            mi=min(mi,dist[i][j]);
        }
        if(mi==inf)
            mi=-1;
        ans[i][time]=mi;
    }
}
int main()
{
    freopen("dd.in","r",stdin);
    freopen("out.txt","w+",stdout);
    int ncase,T=0;
    scanf("%d",&ncase);
    while(ncase--){
        printf("Case #%d: ",++T);
        int n,m,k;
        scanf("%d%d%d",&n,&m,&k);
         init();
        for(int i=1;i<=m;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            add(x,y,i);
            add(y,x,i);
            for(int j=0;j<24;j++){
                scanf("%d",&cost[i][j]);
            }
        }
        for(int i=0;i<24;i++){
            spfa(i,n);
        }
        while(k--){
            int d,s;
            scanf("%d%d",&d,&s);
            printf("%d ",ans[d][s]);
        }
        printf("\n");
    }
    return 0;
}

B题:
题意:题目较长,看了半天,其实就是给你三个数组,A,B,C。(长度不超过2000),和两个数P,Q,问你是否可以从A,B,C中找出4个数,满足 A[x]B[y1]B[y2]C[z]=PQ
其中 y1y2

思路:比赛的时候比较着急,没想到太好的方法,我的写法是首先将 所有的 PC[z]QA[x] 存到一个set中,这样复杂度是 O(NaNclogNaNc) ,然后再枚举所有的 B[y1]B[y2] ,看set中是否存在,如果存在则输出Yes,否则输出No。这一步复杂度是 O(Nb2log(Nb2)) 。以上 Na,Nb,Nc分别是数组A,B,C的长度。代码如下:

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <queue>
#include <set>
#define inf 2100000000
#define ll long long
using namespace std;
struct node{
    ll zi,mu;
    node(){}
    node(ll a,ll b){
        zi=a,mu=b;
    }
    bool operator <(const node &ot)const{
        if(zi==ot.zi){
            return mu<ot.mu;
        }
        return zi<ot.zi;
    }
};
int a[3][2010];
set<node> st;
int main()
{
    freopen("dd.in","r",stdin);
    freopen("out.txt","w+",stdout);
    int ncase,T=0;
    scanf("%d",&ncase);
    while(ncase--){
        st.clear();
        printf("Case #%d:\n",++T);
        scanf("%d%d%d",&a[0][0],&a[1][0],&a[2][0]);
        for(int i=0;i<3;i++){
            for(int j=1;j<=a[i][0];j++)
                scanf("%d",&a[i][j]);
        }
        for(int i=1;i<=a[0][0];i++){
            for(int j=1;j<=a[2][0];j++){
                int x=a[0][i],y=a[2][j];
                int gcd=__gcd(x,y);
                x/=gcd;
                y/=gcd;
                //printf("%d %d\n",x,y);
                st.insert(node(x,y));
            }
        }
        int q;
        scanf("%d",&q);
        while(q--){
            int P,Q,tru=0;
            scanf("%d%d",&P,&Q);
            for(int i=1;i<=a[1][0];i++){
                for(int j=i+1;j<=a[1][0];j++){
                    ll x1=(ll)a[1][i]*P,y1=(ll)a[1][j]*Q;
                    ll gcd=__gcd(x1,y1);
                    x1/=gcd;
                    y1/=gcd;
                    ll x2=(ll)a[1][i]*Q,y2=(ll)a[1][j]*P;
                    gcd=__gcd(x2,y2);
                    x2/=gcd;
                    y2/=gcd;
                    if(st.count(node(x1,y1))!=0||st.count(node(y2,x2))!=0){
                        tru=1;
                        break;
                    }
                }
                if(tru)
                    break;
            }
            if(tru)
                printf("Yes\n");
            else
                printf("No\n");
        }
    }
    return 0;
}

C题:
题意:A,B两个人玩一个游戏,首先给一个数字N,A先手,两人轮流,如果轮到某个人的时候,N的各位上的数字之和是一个质数(1也算)。则此人失败,否则的话,它可以选择N的一个质因数m,将N除以m直到m不是N的质因数为止,然后轮到另一个人。现在给你这个数N,如果两人都使用最优策略,谁必胜。

思路:我记忆化搜索做的,首先将N分解质因数,因为N的范围是不大于 1015 ,其不同质因数个数不会很大。然后就是搜索,如果这个数的各位数之和是质数(包含1),则这个数先手必败。否则,查看这个数的后继状态(就是除掉一个质因数后得到的数),如果有一个是先手必败,那么这个数就是先手必胜,否则是先手必败。搜索过程中用一个map来记录结果。代码如下:

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <queue>
#include <set>
#include <vector>
#include <map>
#define inf 2100000000
#define maxn 40000000
#define ll long long
using namespace std;
map<ll,int> mp;
int p[maxn+10];
vector<ll> vec;
void init(){
    memset(p,0,sizeof(p));
    for(int i=2;i<=maxn;i++){
        int x=i*2;
        if(x>maxn)
            break;
        if(p[i])
            continue;
        while(x<=maxn){
            p[x]=1;
            x+=i;
        }
    }
    for(int i=2;i<=maxn;i++){
        if(!p[i])
            vec.push_back(i);
    }
}
bool ck(ll x){
    int sum=0;
    while(x){
        sum+=x%10;
        x/=10;
    }
    return !p[sum];
}
vector<ll> vis;
int use[30];
int dfs(ll x,int n){
    int ret=mp[x];
    if(ret)
        return ret;

    ret=-1;
    if(ck(x))
        return mp[x]=-1;

    for(int i=0;i<n;i++){
        if(!use[i]){
            use[i]=1;
            if(dfs(x/vis[i],n)==-1){
                ret=1;
                use[i]=0;
                break;
            }
            use[i]=0;
        }
    }
    return mp[x]=ret;
}

int main()
{
    freopen("dd.in","r",stdin);
    freopen("out.txt","w+",stdout);
    init();
    int ncase,T=0;
    scanf("%d",&ncase);
    while(ncase--){
        printf("Case #%d: ",++T);
        ll n,m;
        cin>>n;
        m=n;
        int size=vec.size();
        vis.clear();
        memset(use,0,sizeof(use));
        for(int i=0;i<size;i++){
            if(m==1)break;
            if(m%vec[i]==0){
                ll ret=1;
                while((m%vec[i])==0){
                    ret*=vec[i];
                    m/=vec[i];
                }
                vis.push_back(ret);
            }
        }
        if(m!=1)
            vis.push_back(m);
        if(dfs(n,vis.size())==1)
            printf("Laurence\n");
        else
            printf("Seymour\n");
    }
    return 0;
}

D题:

题意:给你一个只含有abcd四个字符的字符串S。然后称一个序列是合法的Albocede DNA序列当且仅当其满足下列4个条件:
1:至少含有abcd四种字符
2:所有的a在b的前面,所有的b在c的前面,所有的c在d的前面
3:a和c的数量相等
4:b和d的数量相等

现在称一个序列是Albocede-n DNA序列,只要它是一个或者多个Albocede DNA序列拼接而成:
如 abcdaabbbccddd。
求S有多少个子序列(注意不是子串),是Albocede-n DNA序列。这里不同位置得到的子序列当做是不同的。比如aabcd满足要求的子序列有两个。它们都是 abcd。具体可以参考样例。

思路:比赛时着急一开始没看清楚题,搞得死都过不了第四个样例。。。。
这道题可以用动态规划解决:
首先设4个状态:
状态0表示这样的字符串:Xa..ab..bc..cd..d 其中X是Albocede-n DNA序列(可为空),其中a的数量和c的数量一样,d的数量不能唱过b的数量,且大于0(以d结尾)
状态1表示这样的字符串:Xa..a 其中X和上面一样,a的数量大于0(以a结尾)。
状态2表示这样的字符串:Xa..ab..b 其中X和上面定义一样,a的数量和b的数量均大于0(以b结尾)
状态3表示这样的字符串:Xa..ab..bc..c其中 X定义和上面一样,a,b,c的数量均大于0(以c结尾),并且c的数量不能大于a的数量。

有了这三个状态,我们设 dp[i][state][n1][n2]表示S的前i个字符组成的字符串中(就是前缀i),满足状态state,并且a的数量与c的数量之差为n1,b和d的数量之差为n2的子序列的数量。(有点拗口哈。。。)。
那么更新答案就可在 dp[i-1][0][0][1]转移到dp[i][0][0][0]的时候进行。
状态转移就很明显了。
根据S[i]的字符,是a的话只会影响状态0,1的值,b只会影响状态1,2的值,c只会影响状态2,3的值,d只会影响状态3,0的值。具体n1,n2的变化可以根据状态的定义进行变化,具体可以参考代码实现。另外为了节约内存,可以使用滚动数组。代码如下

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <queue>
#include <set>
#include <vector>
#include <map>
#define inf 2100000000
#define mod 1000000007
#define ll long long
using namespace std;
ll dp[2][4][255][255];
char str[510];
void add(ll &x,ll y){
    x=(x+y)%mod;
}
int main(){
    freopen("dd.in","r",stdin);
    freopen("out.txt","w+",stdout);
    int ncase,T=0;
    scanf("%d",&ncase);
    while(ncase--){
        printf("Case #%d: ",++T);
        scanf("%s",str+1);
        int n=strlen(str+1),t=1;
        memset(dp,0,sizeof(dp));
        dp[0][0][0][0]=1;
        ll ans=0;
        for(int i=1;i<=n;i++){
            memcpy(dp[t], dp[1-t], sizeof(dp[t]));
            for(int state=0;state<4;state++){//a-cÊýÁ¿
                for(int j=0;j<=250;j++){//b-dÊýÁ¿
                    for(int k=0;k<=250;k++){
                        if(dp[1-t][state][j][k]==0)
                            continue;
                        ll tmp=dp[1-t][state][j][k];
                        if(str[i]=='a'){
                            if(state==0){
                                if(j==0&&k==0){
                                    add(dp[t][1][1][0],tmp);
                                }
                            }
                            else if(state==1){
                                if(k==0)
                                    add(dp[t][1][j+1][0],tmp);
                            }
                        }
                        else if(str[i]=='b'){
                            if(state==1){
                                if(j>0&&k==0)
                                    add(dp[t][2][j][1],tmp);
                            }
                            else if(state==2){
                                if(j>0)
                                    add(dp[t][2][j][k+1],tmp);
                            }
                        }
                        else if(str[i]=='c'){
                            if(state==2){
                                if(j>0)
                                    add(dp[t][3][j-1][k],tmp);
                            }
                            else if(state==3){
                                if(j>0)
                                    add(dp[t][3][j-1][k],tmp);
                            }
                        }
                        else {
                            if(state==3){
                                if(j==0&&k>0){
                                    add(dp[t][0][0][k-1],tmp);
                                    if(k==1){
                                        add(ans,tmp);
                                    }
                                }
                            }
                            else if(state==0){
                                if(j==0&&k>0){
                                    add(dp[t][0][0][k-1],tmp);
                                    if(k==1)
                                        add(ans,tmp);
                                }
                            }
                        }
                    }
                }
            }
            t=1-t;
        }
        cout<<ans<<endl;
    }
    return 0;
}

你可能感兴趣的:(笔试)