牛客练习赛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)

 
树上操作,线段树或者树剖+线段树。主要是看到修改+查询,反射性想到前两种方法。不过也可能是别的;

 

posted @ 2020-04-12 23:16  SuccessfulRoad  阅读(221)  评论(0编辑  收藏  举报