牛客练习赛 61(待补F-点分治?)

A. 打怪

先求出每次打死一只怪需要掉多少血,然后就直接算出能够打死多少只。

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
    
    
    IO;
    int T=1;
    cin>>T; 
    while(T--)
    {
    
    
        int h,a,H,A;
        cin>>h>>a>>H>>A;
        int cnt=(H+a-1)/a;
        int p=(cnt-1)*A;
        if(p) cout<<(h-1)/p<<'\n';
        else cout<<"-1\n";
    }
    return 0;
}

B. 吃水果

不妨设 n < m n<m n<m,如果我们先吃 k k k次然后加倍一次能够使得 m = n m=n m=n那么需要满足 2 × ( n − k ) = m − k 2×(n-k)=m-k 2×(nk)=mk,得出 k = 2 n − m k=2n-m k=2nm,由此只需先让加倍到 2 n > = m 2n>=m 2n>=m然后吃 k k k次再次加倍然后在吃 m − k m-k mk次即可吃完,由此上面贪心一定最小。

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
    
    
    IO;
    int T=1;
    cin>>T;
    while(T--)
    {
    
    
        int n,m;
        cin>>n>>m;
        if(n>m) swap(n,m);
        int res=m;
        while(n<m)
        {
    
    
            res++;
            n*=2;
        }
        cout<<res<<'\n';
    }    
    return 0;
}

C. 四个选项

首先先用并查集统计出每个连通块的数量,然后把每一个连通块看成一个物品,跑一边背包问题即可。
状态表示: f ( i , j , k , l , r ) f_{(i,j,k,l,r)} f(i,j,k,l,r)考虑前 i i i个物品,答案A选了 j j j个,答案B选了 k k k个,答案C选了 l l l个,答案D选了 r r r个的集合。
状态转移:考虑第 i i i个物品放在哪个答案中不难写出转移。
感觉这方法有点暴力,但是思路应该还是非常好理解

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=15;
int p[N],sz[N];
ll f[N][N][N][N][N];
int find(int x)
{
    
    
    return x==p[x]?x:p[x]=find(p[x]);
}
int main()
{
    
    
    IO;
    int T=1;
    //cin>>T;
    while(T--)
    {
    
    
        for(int i=1;i<=12;i++) p[i]=i,sz[i]=1;
        int a,b,c,d,m;
        cin>>a>>b>>c>>d>>m;
        vector<int> v;
        v.push_back(0);
        while(m--)
        {
    
    
            int a,b;
            cin>>a>>b;
            int pa=find(a),pb=find(b);
            if(pa==pb) continue;
            sz[pb]+=sz[pa];
            p[pa]=pb;
        }
        for(int i=1;i<=12;i++) 
            if(p[i]==i) v.push_back(sz[i]);
        f[0][0][0][0][0]=1;
        int n=v.size()-1;
        for(int i=1;i<=n;i++)
            for(int j=0;j<=a;j++)
                for(int k=0;k<=b;k++)   
                    for(int l=0;l<=c;l++)
                        for(int r=0;r<=d;r++)
                        {
    
    
                            if(j>=v[i]) f[i][j][k][l][r]+=f[i-1][j-v[i]][k][l][r];
                            if(k>=v[i]) f[i][j][k][l][r]+=f[i-1][j][k-v[i]][l][r];
                            if(l>=v[i]) f[i][j][k][l][r]+=f[i-1][j][k][l-v[i]][r];
                            if(r>=v[i]) f[i][j][k][l][r]+=f[i-1][j][k][l][r-v[i]];
                        }
            
        cout<<f[n][a][b][c][d]<<'\n';
    }
    return 0;
}

D.最短路变短了

原图跑一边dijsktra算出dist1[i]表示1~i的最短距离,在跑一边反图算出dist2[i]表示i~n的最短距离。
考虑如果 u → v u\to v uv之间的边取反能够缩短 1 → n 1\to n 1n的最短距离,那么说明目前最短路径一定是 1 → ⋯ → v → u → ⋯ → n 1\to \dots \to v\to u\to \dots \to n 1vun,因此只需要判断该条件是否成立即可得到答案(dist1[v]+dist2[u]+c<dist1[n]

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef pair<ll,int> pli;
const int N=100010,M=400010;
int h1[N],h2[N],e[M],ne[M],idx;
ll w[M];
ll dist1[N],dist2[N];
bool st[N];
struct node
{
    
    
    int u,v;
    ll w;
}E[M];
int n,m,q;
void add(int h[],int a,int b,ll c)
{
    
    
    e[idx]=b;
    ne[idx]=h[a];
    w[idx]=c;
    h[a]=idx++;
}
void dijkstra(int start,int h[],ll dist[])
{
    
    
    memset(dist,0x3f,8*N);
    memset(st,0,sizeof st);
    priority_queue<pli,vector<pli>,greater<pli> >q;
    dist[start]=0;
    q.push({
    
    0,start});
    while(q.size())
    {
    
    
        int t=q.top().second;q.pop();
        if(st[t]) continue;
        st[t]=1;
        for(int i=h[t];i!=-1;i=ne[i])
        {
    
    
            int j=e[i];
            if(dist[j]>dist[t]+w[i])
            {
    
    
                dist[j]=dist[t]+w[i];
                q.push({
    
    dist[j],j});
            }
        }
    }
}
int main()
{
    
    
    IO;
    int T=1;
    //cin>>T;
    while(T--)
    {
    
    
        memset(h1,-1,sizeof h1);
        memset(h2,-1,sizeof h2);
        cin>>n>>m;
        for(int i=1;i<=m;i++)
        {
    
    
            cin>>E[i].u>>E[i].v>>E[i].w;
            add(h1,E[i].u,E[i].v,E[i].w);
            add(h2,E[i].v,E[i].u,E[i].w);
        }
        dijkstra(1,h1,dist1);
        dijkstra(n,h2,dist2);
        cin>>q;
        while(q--)
        {
    
    
            int id;
            cin>>id;
            int u=E[id].u,v=E[id].v,c=E[id].w;
            if(dist1[n]>dist1[v]+dist2[u]+c) cout<<"YES\n";
            else cout<<"NO\n";
        }
    }
    return 0;
}

E.相似的子串

字符串哈希+二分
二分扫一遍序列即可,用哈希表记录出现次数已经最后一次出现的位置。
时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
#include<unordered_map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
const int N=200010,P=131;
unordered_map<ull,pii> mp;
ull h[N],p[N];
int n,k;
char s[N];
ull get(int l,int r)
{
    
    
    return h[r]-h[l-1]*p[r-l+1];
}
bool check(int mid)
{
    
    
    mp.clear();
    for(int i=mid;i<=n;i++)
    {
    
    
        ull v=get(i-mid+1,i);
        if(mp[v].second<=i-mid) 
        {
    
    
            mp[v].first++;
            mp[v].second=i;
            if(mp[v].first>=k) return 1;
        }
    }
    return 0;
}
int main()
{
    
    
    IO;
    int T=1;
    //cin>>T;
    while(T--)
    {
    
    
        cin>>n>>k;
        cin>>s+1;
        p[0]=1;
        for(int i=1;i<=n;i++)
        {
    
    
            p[i]=p[i-1]*P;
            h[i]=h[i-1]*P+s[i]-'a'+1;
        }
        int l=0,r=n;
        while(l<r)
        {
    
    
            int mid=l+r+1>>1;
            if(check(mid)) l=mid;
            else r=mid-1;
        }
        cout<<l<<'\n';
    }
    return 0;
}

F.苹果树

点分治?待补?

猜你喜欢

转载自blog.csdn.net/Fighting_Peter/article/details/108730269