zoukankan      html  css  js  c++  java
  • 牛客练习赛61

    链接:https://ac.nowcoder.com/acm/contest/5026/A
    来源:牛客网

    题目描述

       你是一个勇士,现在你准备去森林刷毛球怪,你有两个属性(血量,攻击力),毛球怪也有这两个属性。当你遭遇一只毛球怪时你们会进入战斗,然后你和毛球怪轮流攻击(你先手),每次使对方的血量减去自己攻击力的数值,当一方的血量小于等于 0 时死亡。现在你想知道在自己活着的前提下最多杀死几只毛球怪

     
    直接暴力,但我比赛时脑抽了~~(果然一边听课一边打比赛是不可能的!!)
    #include<iostream>
    using namespace std;
    int main()
    {
        int t,h,a,H,A;
        cin>>t;
        while(t--)
        {
            cin>>h>>a>>H>>A;
            if(A==0||H==0) cout<<-1<<endl;
            else if(a==0||h==0) cout<<0<<endl;
            else{
                int l=0,m=0;
                if(H%a==0) l=H/a;
                else l=H/a+1;
                if(l>1)
                {
                    m=h/((l-1)*A);
                    if(h%((l-1)*A)==0) m--;
                         cout<<m<<endl;               
                }
                else cout<<-1<<endl;
            }
        }
    }

    链接:https://ac.nowcoder.com/acm/contest/5026/B
    来源:牛客网

    题目描述

           最近米咔买了n个苹果和m个香蕉,他每天可以选择吃掉一个苹果和一个香蕉(必须都吃一个,即如果其中一种水果的数量为0,则他不能进行这个操作),或者使用魔法将某一种水果的数量翻倍。
          现在米咔想吃西瓜了,但是他的主人赛小息不让他买新水果,除非苹果和香蕉没有了,即数量都是0了。

          现在米咔想知道,最少用多少天他可以吃光苹果和香蕉。

          可以证明的是,一定存在一种方案可以让米咔在若干天后吃光苹果和香蕉。

    emm。。题解很清楚。我刚开始想的是,n!=m的时候,最后都会吃到 某种水果剩余1 另一种为x的情况。但显然不是很好的策略。为了让天数最少,那么最可能的就是

    是两者最为接近;就是题解上写的,让x=min(m,n)不断乘2与y=max(n,m)接近。导致x>y/2&&x<=y;此时,令t=y-x,则(x大于t,因为x>y/2,所以x一定大于t)x减小到t,此时y=2*t。差不多是倍增思想

    #include<iostream>
    #include<algorithm>
    using namespace std;
    bool check(int x)
    {
        int ans=0;
        while(x)
        {
            x>>=1;
            if(x%2) return 0;
            ans++;
        }
        return ans;
    }
    int main()
    {
        int t,n,m;
        cin>>t;
        while(t--)
        {
            cin>>n>>m;
            if(n<m) swap(n,m);
            int k=0;
            if(n==m) {cout<<n<<endl;continue;}
            while(2*m<n) m=m*2,k++;
            int t=n-m;
            k+=m+t+1;
            cout<<k<<endl;
        }

    链接:https://ac.nowcoder.com/acm/contest/5026/C
    来源:牛客网

    题目描述

         众所周知,高考数学中有一个题目是给出12个单项选择,每一个选择的答案是 A,B,C,D 中的一个。

         网上盛传答案存在某种规律,使得蒙对的可能性大大增加。于是今年老师想让你安排这12个题的答案。但是他有一些条件,首先四个选项的数量必须分别为 na,nb,nc,nd。其次有 m 个额外条件,分别给出两个数字 x,y,代表第 x 个题和第 y 个题的答案相同。 现在你的老师想知道,有多少种可行的方案安排答案。
     
    这题一看到就想的是dp[i][a][b][c],到第i题时,a,b,c还剩多少。后面就没思路了~~~~~~(>_<)~~~~(我就是个菜鸟),who know?题解给了个dfs连通块,长见识了~~表示我需要考虑一会儿^^,emm..这道题真邪门了~~我按照dfs联通块的写法,跟ac代码比对,非得说我的代码超内存!!!气得我准备换种写法
    思路是,直接dfs即可,相当于枚举每一种方法,数据较小,直接枚举。或者
    建立一个num数组,记录不同的连通块(每个连通块里面放的是答案相同的题),num【i】代表与i题答案相同的题数,tot记录不同的连通块个数;
    之后两种方法:1、dfs 2、dp
    所以只是因为我函数返回值为int,~~~表示不能理解
     
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define maxn 10000
    int num[maxn],m,head[maxn],val[maxn],ans=0,tot=0,cnt,na,nb,nc,nd;
    struct edge{
        int nx,to;
    }edge[maxn];
    void add(int u,int v)
    {
        edge[++cnt].nx=head[u];
        edge[cnt].to=v;
        head[u]=cnt;
    }
    void dfs1(int u)
    {
        num[tot]++;val[u]=1;
        for(int i=head[u];i;i=edge[i].nx)
        {
            int v=edge[i].to;
            if(!val[v]) dfs1(v);
        }
    }
    void dfs(int x,int a,int b,int c,int d) {
        if(x == tot + 1) {
            ans++;return;
        }
        if( a>=num[x])
            dfs(x+ 1,a - num[x],b,c,d);
        if(b>=num[x])
            dfs(x+ 1,a,b - num[x],c,d);
        if( c>=num[x])
            dfs(x + 1,a,b,c - num[x],d);
        if( d>=num[x])
            dfs(x + 1,a,b,c,d - num[x]);
    }
    int main()
    {
        cin>>na>>nb>>nc>>nd>>m;
        for(int i=1;i<=m;i++)
        {
             int x,y;
            cin>>x>>y;
            add(x,y),add(y,x);
        }
        for(int i=1;i<=12;i++)
        {
            if(!val[i])
            {
                ++tot;dfs1(i);
            }
        }
        dfs(1,na,nb,nc,nd);
        cout<<ans;
        return 0;
    }

    题目描述

            给定一个有向带权图,其中包括 n个城市,城市编号从1 到n,有向边的编号从 1 到 m,现在有一个人位于城市 1,并且想要到城市n旅游。现在政府正在决定将一条道路反向,这个人想知道在某一指定道路反向的情况到达城市n最短路径长度会不会变短。

            保证开始给定的图从城市1可以到达城市n,若边反向后城市1不能到达城市n,我们视为最短路径长度没有变短。

     
    想的时候,最短路,跑一遍Dijkstra。想的是用一个数组记录所经历的边,如果询问时有这条边,那么输出no,因为该路已经是最短。但是如果没经历过,并且原来是反向边,就没办法了!!!一般想的有1、建立反向图 2、建立无向图 ;鉴于本人就是个萌新,卡住了!!;
    看了题解发现,真的是建立个反向图(当时卡的是,建立反向图的话不一定能够到达终点。但本题反向图不必非要到达终点,只需要在反向图中,知道从终点到某点的最短距离,即可。)题解写的很清楚了!!我写一遍,加深理解^^~~
     

    正向跑一遍记录在dis【】;

    反向跑一遍记录在dis1【】;

    假设反向u->v的边,则为1->v->u->n,即值变为dis【v】+dis1【u】+w(u,v),将值与dis[u]进行比较;

    代码重复部分有点多~~

    #include<iostream>
    #include<algorithm>
    #include<queue>
    #include<cstring>
    using namespace std;
    #define maxn 500000
    long long n,cnt,head[maxn],cnt1,head1[maxn],m,dis[maxn],dis1[maxn];
    struct node{
        long long u,dis;
        bool operator<(const node&rhs)const{
        return dis>rhs.dis;}
    };
    struct edge{
        long long nx,to;
        long long w;
        long long num;
    }edge[maxn];
    struct edge1{
        long long nx,to;
        long long w;
        long long num;
    }edge1[maxn];
    struct e{
        long long u,v,w;
    }e[maxn];
    void add(long long u,long long v,long long w,long long i)
    {
        edge[++cnt].nx=head[u];
        edge[cnt].to=v;
        edge[cnt].w=w;
        edge[cnt].num=i;
        head[u]=cnt;
    }
    void add1(long long u,long long v,long long w,long long i)
    {
        edge1[++cnt1].nx=head1[u];
        edge1[cnt1].to=v;
        edge1[cnt1].w=w;
        edge1[cnt1].num=i;
        head1[u]=cnt1;
    }
    void bfs(long long s)
    {
        priority_queue<node> Q;
        Q.push((node){s,0});
        dis[s]=0;
        while(!Q.empty())
        {
            node f=Q.top();
            Q.pop();
            long long u=f.u,d=f.dis;
            if(d>dis[u]) continue;
            for(long long i=head[u];i;i=edge[i].nx)
            {
                long long v=edge[i].to,w=edge[i].w;
                if(dis[v]>dis[u]+w){
                    dis[v]=dis[u]+w;
                    Q.push((node){v,dis[v]});
                }
            }
        }
     }
     void bfs1(long long s)
    {
        priority_queue<node> Q;
        Q.push((node){s,0});
        dis1[s]=0;
        while(!Q.empty())
        {
            node f=Q.top();
            Q.pop();
            long long u=f.u,d=f.dis;
            if(d>dis1[u]) continue;
            for(long long i=head1[u];i;i=edge1[i].nx)
            {
                long long v=edge1[i].to,w=edge1[i].w;
                if(dis1[v]>dis1[u]+w){
                    dis1[v]=dis1[u]+w;
                    Q.push((node){v,dis1[v]});
                }
            }
        }
     }
    int main()
    {
        cin>>n>>m;
        memset(dis,0x3f,sizeof(dis));
        memset(dis1,0x3f,sizeof(dis1));
        for(long long i=1;i<=m;i++)
        {
            long long u,v,c;
            cin>>u>>v>>c;
            e[i].u=u,e[i].v=v,e[i].w=c;
            add(u,v,c,i);add1(v,u,c,i);
        }
        bfs(1);
        bfs1(n);
        int q=0;
        cin>>q;
        while(q--)
        {
            long long x;
            cin>>x;
            long long val=(long long)(dis[e[x].v]+dis1[e[x].u]+e[x].w);
            if(val<(long long)dis[n]) cout<<"YES"<<endl;
            else cout<<"NO"<<endl;
        }
    }

    链接:https://ac.nowcoder.com/acm/contest/5026/E
    来源:牛客网

    题目描述

       给定一个字符串,要求取出k个位置不相交的子串,且他们之间任意两个的最长公共前缀的长度均不小于x。现在给出k,求最大的x。
       两个字符串str1,str2的公共前缀为x指str1和str2的长度均不小于x且这两个字符串的前x个字符对应相同。最长公共前缀即所有的公共前缀里最长的那个,如没有公共前缀则视为最长公共前缀长度为0。
     
    最长公共前缀,lcp。二分+hash。二分最长前缀的长度。左边界=0,右边界为子字符串最长strlen(s)/k。还有就是需要知道长度为x时的方法数;
    用dp来做,dp【i】为到达i时的方法数,dp【i】=dp【j】+1(j>=i+x&&hash[i]=hash[j]),暴力枚举,显然超时;
    则用unordered_map<hash,dp>。题解很详细,长见识了,对于map的用法!!看代码!!
     
    #include<iostream>
    #include<algorithm>
    #include <unordered_map>  
    #include<cstring>
    #include <bits/stdc++.h>
    using namespace std;
    #define p 127
    #define ll long long
    #define maxn 300000
    unsigned long long Hash[500000],pow1[maxn];
    ll dp[500000];
    char s[maxn];
    ll n,k;
    #define re register
    #define il inline
    il long long read()
    {
        re ll x=0,f=1;char c=getchar();
        while(c<'0'||c>'9'){
            if(c=='-') f=-1;c=getchar();
        }
        while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
        return x*f;
    }
    unsigned long long hash1(ll i,ll mid)//hash初始化
    {
        return Hash[i+mid-1]-Hash[i-1]*pow1[mid];
    }
    bool check(ll mid)
    {
        long long num=0;
        dp[0]=0;
        unordered_map<unsigned long long,ll> MAP;
        for(ll i=n-mid+1;i>0;i--)//倒序枚举,也可以用正序,hash就需要倒序了~~
        {
            MAP[hash1(i+mid,mid)]=dp[i+mid];//可以手动模拟一下。MAP<hash,dp>,对于从i开始串长为mid的哈希值,赋值给dp【i+mid】,
            dp[i]=MAP[hash1(i,mid)]+1;//当前dp【i】为hash中与该子串值相同+1,感觉解释的有点错误~~手动模拟吧,应该就会了
            num=max(num,dp[i]);
        }
        if(num<k) return false;
        else return true;
    }
    int main()
    {
        n=read(),k=read();
        cin>>s+1;
        for(ll i=1;i<=n;i++)
        Hash[i]=Hash[i-1]*p+s[i]-'a';
        ll l=0,r=n/k+1,ans=0;
        pow1[0]=1;
        for(ll i=1;i<=n;i++)
            pow1[i]=pow1[i-1]*p;//初始化pow1数组
       while(l<=r)
       {
            ll mid=(l+r+1)>>1;//扩大一点搜索范围,保险~~
            if(check(mid)) ans=max(ans,mid), l=mid+1;
            else r=mid-1;
        }
        cout<<ans;
        return 0;
    }
     

    题目描述

           给定一个由n个点和n-1条边组成的无向连通图(即一棵树),每一条边都有一个权值代表走过它所需要的时间花费,每个点上面有初始有一个苹果,每个苹果有一个成熟度。

           由于苹果不熟或者熟的太透了都不会好吃,所以现在米咔想摘一个成熟度在范围[x,y]的苹果来做苹果派。现在需要你来执行m条操作。

           1 u x:在某一个点u新出现了一个成熟度为x的苹果。(1≤u≤n,1≤x≤10000)

           2 u x y:询问米咔从某一个点u出发,去摘一个成熟度在[x,y]范围内的苹果并回到u的最小时间花费。(1≤u≤n,1≤x≤y≤10000)

     
    树上操作,线段树或者树剖+线段树。主要是看到修改+查询,反射性想到前两种方法。不过也可能是别的;
  • 相关阅读:
    19、spring注解学习(声明式事务)——spring注解版声明式事务
    Visual C# 2015调用SnmpSharpNet库实现简单的SNMP元素查询
    SNMP协议交互学习-获取udp的udpindatagrams
    LwIP的SNMP学习笔记
    stm32f407使用Keil uV5建立工程日志
    IP unnumbered interface,某个接口不编号,某个接口不分配IP地址
    OSPFv3与OSPFv2协议的比较
    卫星网络-拓扑优化-文献笔记
    卫星轨道相关笔记SGP4
    [20190226]删除tab$记录的恢复6.txt
  • 原文地址:https://www.cnblogs.com/Showend/p/12683055.html
Copyright © 2011-2022 走看看