Google Kick Start 2020 --Round E

Longest Arithmetic

题意

给一个长为n的数组,求其中最长的等差子串长度。

思路

2开始遍历,维护上一个差,然后判断当前ii-1的差是否相等。同时记录答案

代码

#include<bits/stdc++.h>

using namespace std;

const int MAX=2e5+5;

int a[MAX];

int main()
{
    int T,cas=0;
    scanf("%d",&T);
    while(T--)
    {
        int n,res=2;
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            scanf("%d",&a[i]);
        int d=a[1]-a[0],cur=2;
        for(int i=2;i<n;i++)
        {
            if(a[i]-a[i-1]==d)cur++;
            else cur=2,d=a[i]-a[i-1];
            res=max(res,cur);
        }
        printf("Case #%d: %d\n",++cas,res);
    }
}

Toys

题意

n个玩具,编号从1-n,每个玩具有玩耍时间E和冷却时间Ri号玩具可以玩Ei时间,然后回进入长Ri的冷却时间。现在从1开始,循环玩各个玩具(n完了继续玩1),同时可以丢掉任意数量的玩具,求最少丢多少玩具能无限玩下去,如果不能无限玩下去,则给出最少丢多少玩具能得到最长游玩时间。

思路

记所有玩耍时间之和为sum,可以发现如下结论:

  • 对于某个玩具i,当且仅当Ri<=sum-Ei时,即Ri+Ei<=sum,才能在第二次轮到i时继续玩下去(即将其他所有玩具玩一遍的时间大于等于i的冷却时间)

因为玩玩具是按顺序的,所以可以动态维护当前剩余的玩具的cur_sum,从1-n动态加入i号玩具,每次加入后更新cur_sum,然后贪心的从大到小的删除所有大于cur_sumRi+Ei,并且每次删除后都记录当前最多能玩多久。如果最后所有玩具都被删除,那说明不能永久玩下去,输出最长游玩时间。如果最后剩余一些玩具,那么说明可以永久玩下去,输出删除玩具的个数。

其实不贪心也可以,只要删除所有Ri+Ei>cur_sum就可以,不过用优先队列可以自动排序不用遍历,比较方便。

代码

#include<bits/stdc++.h>

using namespace std;
using ll=long long;

const int MAX=1e5+5;

int a[MAX],b[MAX];

struct cmp{bool operator()(int x,int y){return a[x]+b[x]<a[y]+b[y];}};

priority_queue<int,vector<int>,cmp> Q;

int main()
{
    int T,cas=0;
    scanf("%d",&T);
    while(T--)
    {
        while(!Q.empty())Q.pop();
        int n,totdel=0,maxxdel=0;
        ll sum=0;
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            scanf("%d%d",&a[i],&b[i]),sum+=a[i];
        ll cursum=sum,maxx=sum,curtime=sum;
        for(int i=0;i<n;i++)
        {
            Q.push(i);
            curtime+=a[i];
            while(!Q.empty())
            {
                int x=Q.top();
                if(a[x]+b[x]<=cursum)break;
                cursum-=a[x];
                curtime-=a[x]*2;
                Q.pop();
                totdel++;
            }
            if(curtime>maxx)
            {
                maxx=curtime;
                maxxdel=totdel;
            }
        }
        if(totdel==n)
            printf("Case #%d: %lld %d\n",++cas,maxx,maxxdel);
        else
            printf("Case #%d: INDEFINITELY %d\n",++cas,totdel);
    }
}

Golden Stone

题意

s种石头,编号从1-s,编号1的石头是黄金石头。然后给一张无向图,图中部分节点可以免费获取某种编号的石头,可以将某一块石头花费1的代价从一个节点转移到另一个节点。并且存在某些可以在任何节点无代价在合成石头的配方,如2 3 4可以合成1。求获得一块黄金石头的最小代价。

思路

很容易可以想到dp,设状态dp[i][j]表示在节点i获得一块编号为j的石头的代价。可以在图上bellman-ford跑一遍,推出dp[i][j]。但是还有配方没有考虑。实际上配方可以在bellman-ford跑的过程中一并维护。每次从队列中读取到一个节点u,可以遍历配方,查看是否可以用配方更新状态,如果可以更新,就再次把u放入队列中。这样对每个节点 u,最多因为配方更新入队两次,因此时间复杂度为在图上bellman-ford跑一遍的两倍。

也可以用分层图求最短路的模型求解,但是要麻烦许多。

代码

#include<bits/stdc++.h>

using namespace std;
using ll=long long;
const int MAX=305;
const ll INF=1e12;

vector<int> G[MAX];
vector<vector<int> >rcp[MAX];
ll dp[MAX][MAX];
bool inque[MAX];
int n,m,s,r;

void bfs()
{
    queue<int>Q;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=s;j++)
            if(dp[i][j]==0){inque[i]=1,Q.push(i);break;}
    while(!Q.empty())
    {
        int u=Q.front();
        Q.pop();
        inque[u]=0;
        for(int i=1;i<=s;i++)
            for(int j=0;j<rcp[i].size();j++)
            {
                ll sum=0;
                for(int k=0;k<rcp[i][j].size();k++)
                    sum+=dp[u][rcp[i][j][k]];
                if(sum<dp[u][i])dp[u][i]=sum,inque[u]=1,Q.push(u);
            }
        int len=G[u].size();
        for(int i=0;i<len;i++)
        {
            int v=G[u][i];
            for(int j=1;j<=s;j++)
            {
                if(dp[v][j]>dp[u][j]+1)
                {
                    dp[v][j]=dp[u][j]+1;
                    if(!inque[v]) inque[v]=1,Q.push(v);
                }
            }
        }
    }
}

int main()
{
    int T,cas=0;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d%d",&n,&m,&s,&r);
        for(int i=1;i<=n;i++)
        {   inque[i]=0;
            G[i].clear();
            for(int j=1;j<=s;j++)
                dp[i][j]=INF,rcp[j].clear();
        }

        for(int i=0;i<m;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        for(int i=1;i<=n;i++)
        {
            int k;
            scanf("%d",&k);
            for(int j=0;j<k;j++)
            {
                int x;
                scanf("%d",&x);
                dp[i][x]=0;
            }
        }
        for(int i=0;i<r;i++)
        {
            int k;
            scanf("%d",&k);
            vector<int>rr;
            rr.clear();
            for(int j=0;j<k;j++)
            {
                int x;
                scanf("%d",&x);
                rr.push_back(x);
            }
            scanf("%d",&k);
            rcp[k].push_back(rr);
        }
        bfs();
        ll res=INF;
        for(int i=1;i<=n;i++)
            res=min(res,dp[i][1]);
        if(res==INF)res=-1;
        printf("Case #%d: %lld\n",++cas,res);
    }
}

posted @ 2022-11-23 16:41  cryingrain  阅读(26)  评论(0编辑  收藏  举报