牛客练习赛89

传送门

A

#include<bits/stdc++.h>
using namespace std;
#define int unsigned long long
int n,k,s;
vector<int>v;
unordered_map<int,int>mp;
signed main(){
    cin>>n>>k>>s;
    for(int i=1;i<=k;i++){
        int x;
        cin>>x;
        mp[x]=1;
    }
    for(int i=0;i<64;i++){
        int t=s>>i&1;
        if(t==1&&mp[i+1]==1){puts("NO");return 0;}
    }
    puts("YES");
    
}

B

dfs版本

#include<bits/stdc++.h>
using namespace std;
string s;
string a="cocacola";
int ans=0x3f3f3f3f;
void dfs(string x,int cnt){
    if(x==a){
        ans=min(ans,cnt);
        return;
    }
    for(int i=0;i<8;i++){
        if(x[i]==a[i])continue;
        for(int j=0;j<8;j++){
            if(x[j]!=a[j]&&x[j]==a[i]){
                swap(x[i],x[j]);
                dfs(x,cnt+1);
                swap(x[i],x[j]);
            }
        }
    }
}
signed main(){
    cin>>s;
    dfs(s,0);
    cout<<ans;
}

bfs版本

从终点出发,用哈希表处理出到达每一步的min
感觉这个更好更加适用

#include<bits/stdc++.h>
using namespace std;
string s;
string a="cocacola";
int ans=0x3f3f3f3f;
unordered_map<string,int>mp;
queue<string>q;
void bfs(string start){
    mp[start]=0;
    q.push(start);
    while(!q.empty()){
        auto t=q.front();
        q.pop();
        for(int i=0;i<8;i++){
            for(int j=0;j<8;j++){
                if(t[i]==t[j])continue;
                string x=t;
                swap(x[i],x[j]);
                if(mp.count(x))continue;
                mp[x]=mp[t]+1;
                q.push(x);
            }
        }
    }
}
signed main(){
    cin>>s;
    bfs(a);
    cout<<mp[s];
}

C

#include<bits/stdc++.h>
using namespace std;
int n,m;
const int N=1e6+10;
int a[N][4];
int vis[N][4];
signed main(){
    cin>>n>>m;
    while(m--){
        int x,y;
        cin>>y>>x;
        a[x][y]=1;
    }
    bool ok=1;
    if(a[2][1]||a[1][2])ok=0;
    for(int x=2,y=1;x<=n&&y<=2;){
        vis[x][y]=1;
        if(x<n&&a[x+1][y]==0)x++;
        else if(a[x][y+1]==0)y++;
        else {
            ok=0;
            break;
        }
    }
    int x=1,y=2;
    for(;x<n&&y<=3;){
        if(a[x+1][y]==0&&vis[x+1][y]==0)x++;
        else y++;
    }
    if(x!=x-1&&y!=3)ok=0;
    if(ok)puts("YES");
    else puts("NO");
}

D

在这里插入图片描述
prufer

在这里插入图片描述

我们可以轻松地发现这道题是一道dp的题目
对于整张图来说,总共有2*n-2地度数,由于每一个点都至少有一个度数,我们就只剩下n-2的度数可以进行自由分配
我们将每个点看做一个点加上一条没有连上其他点的边,然后在更新的时候将所有点联向当前树的叶子节点上,然后根据其度数做一下背包就好了
f[i] 表示树上已经有i 个点的最佳权值
假设度数为i的贡献为a[i],当一个节点插入的时候,会损失a[1]的价值,增加a[i-j+1]的价值,所以转移方程为
f[i]=max(f[i],f[j]+a[i-j+1]-a[1]),1<=j<=i;

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+10;
#define int long long
int n;
int f[N];//f[i]表示分配i的度数的时候,整棵树权值和 最大能多大
int a[N];
signed main(){
    cin>>n;
    for(int i=1;i<n;i++)cin>>a[i];
    memset(f,-0x3f,sizeof f);
    f[0]=0;
    for(int i=1;i<=n-1;i++){//枚举物品
        for(int j=i;j<=n-2;j++){//枚举体积,(方案数
            f[j]=max(f[j] , f[j-i]+a[i+1]-a[1]);
        }
    }
    cout<<f[n-2]+n*a[1];
}

反思:
这道题难就难在怎么把这棵树的形状对应权值和的计算
== 转化为==
== 完全背包问题==
首先每个点都要加在树上
所以初始状态可以看成一个点连了一条边(没有连上另一个节点
总度数本来是2*(n-1)=n+n-2
减去初始的n个度数之后,题目就变成了如何将n-2的度数分配使得权值和最大
也就是说我现在有n-2块钱
要买2个鸡翅,4杯可乐,6个汉堡
这样分配我的12块钱可以使得价值最大化
所以说如果你理解了这个转化为完全背包的过程代码还可以这样写

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+10;
#define int long long
int n;
int a[N];
int f[N];
signed main(){
    cin>>n;
    for(int i=1;i<n;i++)cin>>a[i];
    memset(f,-0x3f,sizeof f);
    f[0]=n*a[1];
    for(int i=1;i<=n-2;i++){
        for(int j=i;j<=n-2;j++){
            f[j]=max(f[j] , f[j-i]+a[i+1]-a[1]);
        }
    }
    cout<<f[n-2];
}

因为是完全背包,所以枚举体积的时候要正序枚举


E

在这里插入图片描述
数论+容斥原理

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,a,n) for(int i=n;i>=a;i--)
#define pb push_back
#define SZ(v) ((int)v.size())
#define fs first
#define sc second
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
int T;
const ll inf=1e15,mod=998244353;
ll l,r,cnt[55][32],num[55][32];
ll solve(ll x){
    memset(cnt,0,sizeof(cnt));
    rep(i,0,50){
        rep(j,0,25){
            if(num[i][j])    cnt[i][j]=x/num[i][j];
        }
    }
    ll ret=0;
    per(k,0,75){
        rep(i,0,min(k,50)){
            int j=k-i;
            if(j>25)    continue;
            if(cnt[i][j]){
                ret+=((ll)(max(i,j)+1)*(cnt[i][j]-1));
                rep(ii,0,i){
                    rep(jj,0,j){
                        cnt[ii][jj]-=cnt[i][j];
                    }
                }
            }
        }
    }
    return ret;
}
int main(){
    rep(i,0,50){
        if(!i)    num[i][0]=1;
        else    num[i][0]=2ll*num[i-1][0];
        rep(j,1,25){
            num[i][j]=num[i][j-1]*5ll;
            if(num[i][j]>inf){
                break;
            }
        }
    }
    cin>>T;
    while(T--){
        scanf("%lld%lld",&l,&r);
        assert(l<=r&&l>0&&r>0&&r<=inf);
        printf("%lld\n",(solve(r)-solve(l-1))%mod);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值