牛客寒假算法训练营1

A DFS搜索
设置匹配量匹配
通过前一个做标记来完成查找 复杂度O(NT)

#include<bits/stdc++.h>
#define int long long
#define all(x) x.begin(),x.end()
#define rall(x) x.rbegin(),x.rend()
#define pb push_back 
#define pii pair<int,int>
using namespace std;
inline int read(){
    int a=0;int b=1;char c=getchar();
    while(c<48||c>57){if(c=='-')b=-1;c=getchar();}
    while(c<=57&&c>=48){a*=10;a+=c-48;c=getchar();}return a*b;
}
void solve(){
    int n=read();
    string s;
    cin>>s;
    int ans1=-1,ans2=-1;
    for(int i=0;i<n;i++){
        if(ans1==-1&&s[i]=='D')ans1=i;
        if(ans1!=-1&&s[ans1]=='D'&&s[i]=='F')ans1=i;
        if(ans1!=-1&&s[ans1]=='F'&&s[i]=='S')ans1=i;
        if(ans2==-1&&s[i]=='d')ans2=i;
        if(ans2!=-1&&s[ans2]=='d'&&s[i]=='f')ans2=i;
        if(ans2!=-1&&s[ans2]=='f'&&s[i]=='s')ans2=i;
    }
    if(s[ans1]=='S')ans1=1;else ans1=0;
    if(s[ans2]=='s')ans2=1;else ans2=0;
    cout<<ans1<<" "<<ans2<<endl;
}
signed main(){
    int _=1;
    _=read();
    while(_--)solve();
}


M 牛客老粉才知道的秘密
根据题意看出 m%6的关系来判断是否乘二


#include<bits/stdc++.h>
#define int long long
#define all(x) x.begin(),x.end()
#define rall(x) x.rbegin(),x.rend()
#define pb push_back 
#define pii pair<int,int>
using namespace std;
inline int read(){
    int a=0;int b=1;char c=getchar();
    while(c<48||c>57){if(c=='-')b=-1;c=getchar();}
    while(c<=57&&c>=48){a*=10;a+=c-48;c=getchar();}return a*b;
}
void solve(){
    int n=read();
    int ans=n/6;
    if(n%6!=0)ans*=2;
    cout<<ans<<endl;
}
signed main(){
    int _=1;
    _=read();
    while(_--)solve();
}


E 本题又主要考察了贪心
直接DFS爆搜 
做题时发现的问题 多元搜索时回归后忘记删除标记

#include<bits/stdc++.h>
#define int long long
#define all(x) x.begin(),x.end()
#define rall(x) x.rbegin(),x.rend()
#define pb push_back 
#define pii pair<int,int>
using namespace std;
inline int read(){
    int a=0;int b=1;char c=getchar();
    while(c<48||c>57){if(c=='-')b=-1;c=getchar();}
    while(c<=57&&c>=48){a*=10;a+=c-48;c=getchar();}return a*b;
}
struct node{
    int id,x;
};
bool cmp(node a,node b){
    if(a.x==b.x)return a.id<b.id;
    return a.x>b.x;
}
int n,m,mc;
int a[105],u[105],v[105];
node b[105];
void dfs(int dep){
    if(dep==m){
        for(int i=1;i<=n;i++)b[i].id=i;
        for(int i=1;i<=n;i++)b[i].x=a[i];
        sort(b+1,b+n+1,cmp);
        for(int i=1;i<=n;i++){
            if(b[i].id==1){
                mc=min(mc,i);
                return;
            }
        }
    }
    a[u[dep]]+=3;
    dfs(dep+1);
    a[u[dep]]-=3;
    a[v[dep]]+=3;
    dfs(dep+1);
    a[u[dep]]+=1;
    a[v[dep]]-=2;
    dfs(dep+1);
    a[u[dep]]--;
    a[v[dep]]--;
}
void solve(){
    n=read(),m=read();
    mc=n;
    for(int i=1;i<=n;i++)a[i]=read();
    for(int i=0;i<m;i++)u[i]=read(),v[i]=read();
    dfs(0);
    cout<<mc<<endl;
}
signed main(){
    int _=1;
    _=read();
    while(_--)solve();
}


B 关鸡
通过左边两团火和右边两团火的方式来和特判(1,-1),(1,1),(2,0)之间的关系
比赛时写了一堆屎山代码导致逻辑不清
以后需要注意代码简洁
代码参考jiangly
#include<bits/stdc++.h>
#define int long long
#define all(x) x.begin(),x.end()
#define rall(x) x.rbegin(),x.rend()
#define pb push_back
#define pii pair<int,int>
using namespace std;
inline int read(){
    int a=0;int b=1;char c=getchar();
    while(c<48||c>57){if(c=='-')b=-1;c=getchar();}
    while(c<=57&&c>=48){a*=10;a+=c-48;c=getchar();}return a*b;
}
void solve(){
    int n=read();
    int left1=0,left2=0,right1=0,right2=0;
    set<pii>s;
    for(int i=1;i<=n;i++){
        int r=read(),c=read();
        s.emplace(r,c);
        if(c<=0)left1=1;
        if(c>=0)right1=1;
    }
    for(auto [r,c]:s){
        if(!c)continue;
        if(s.count({r^3,c})||s.count({r^3,c+(c>0?-1:1)})){
            if(c<0)left2=1;
            else right2=1;
        }
    }
    int ans=4-right2-right1-left1-left2;
    int res=3-s.count({1,1})-s.count({1,-1})-s.count({2,0});
    ans=min(ans,res);
    cout<<ans<<endl;
}
signed main(){
    int _=1;
    _=read();
    while(_--)solve();
}
C 按闹分配
对所有人做前缀和
由题意得 所处的位置为m/tc向下取整
#include<bits/stdc++.h>
#define int long long
#define all(x) x.begin(),x.end()
#define rall(x) x.rbegin(),x.rend()
#define pb push_back
#define pii pair<int,int>
using namespace std;
inline int read(){
    int a=0;int b=1;char c=getchar();
    while(c<48||c>57){if(c=='-')b=-1;c=getchar();}
    while(c<=57&&c>=48){a*=10;a+=c-48;c=getchar();}return a*b;
}
void solve(){
    int n=read(),q=read(),c=read();
    vector<int>a(n),sum(n,0);
    for(int i=0;i<n;i++)a[i]=read();
    sort(all(a));
    sum[0]=a[0];
    for(int i=1;i<n;i++){
        sum[i]=sum[i-1]+a[i];
    }
    while(q--){
        int m=read();
        int pos=m/c;
        pos=min(pos,n-1);
        pos=n-pos-1;
        cout<<(c*n>m)*sum[pos]+c<<endl;
    }
}
signed main(){
    int _=1;
//    _=read();
    while(_--)solve();
}
G why买外卖
对其以a为大小进行排序
不断为折扣加上b因为最后的值肯定大于前面的a必定可以减去折扣
#include<bits/stdc++.h>
#define int long long
#define all(x) x.begin(),x.end()
#define rall(x) x.rbegin(),x.rend()
#define pb push_back
#define pii pair<int,int>
using namespace std;
inline int read(){
    int a=0;int b=1;char c=getchar();
    while(c<48||c>57){if(c=='-')b=-1;c=getchar();}
    while(c<=57&&c>=48){a*=10;a+=c-48;c=getchar();}return a*b;
}
void solve(){
    int n=read(),m=read();
    vector<pii>a(n);
    for(int i=0;i<n;i++){
        int x=read(),y=read();
        a[i]={x,y};
    }
    sort(all(a));
    int ans=m,sum=0;
    for(auto [x,y]:a){
        sum+=y;
        if(x-sum<=m){
            ans=max(ans,sum+m);
        }
    }
    cout<<ans<<endl;
}
signed main(){
    int _=1;
    _=read();
    while(_--
    )solve();
}
L 要有光
由题意可得z为0时面积最大 S为3倍最小的三角形即3*w*c 
#include<bits/stdc++.h>
#define int long long
#define all(x) x.begin(),x.end()
#define rall(x) x.rbegin(),x.rend()
#define pb push_back
#define pii pair<int,int>
using namespace std;
inline int read(){
    int a=0;int b=1;char c=getchar();
    while(c<48||c>57){if(c=='-')b=-1;c=getchar();}
    while(c<=57&&c>=48){a*=10;a+=c-48;c=getchar();}return a*b;
}
void solve(){
    int c=read(),d=read(),h=read(),w=read();
    cout<<3*w*c<<endl;
}
signed main(){
    int _=1;
    _=read();
    while(_--)solve();
}
I It's bertrand paradox. Again!
使用随机数生成 来暴力枚举概率
这里使用了x和y的绝对值分布来写
其中发现使用
#define int long long 
和mt19937时产生了奇怪的bug
bit-noob的枚举 绝对值在950000左右
void solve(){
    int n=100000;
    mt19937 rng;
    int sum=0;
    for(int i=0;i<n;i++){
        int x,y,r;
        x=rng() % 199 - 99;
        y=rng() % 199 - 99;
        do{
            r=rng() % 100+1;
        }
        while(x+r>100||x-r<-100||y+r>100||y-r<-100);
        sum+=abs(x)+abs(y);
    }
    cout<<sum<<endl;
}
buaa-noob的枚举 绝对值在750000左右
void solve(){
    int n=100000;
    mt19937 rng;
    int sum=0;
    for(int i=0;i<n;i++){
        int x,y,r;
        do{
            x=rng() % 199 - 99;
            y=rng() % 199 - 99;
            r=rng() % 100+1;
        }
        while(x+r>100||x-r<-100||y+r>100||y-r<-100);
        sum+=abs(x)+abs(y);
    }
    cout<<sum<<endl;
}
解题代码如下
#include<bits/stdc++.h>
//#define int long long
//#define all(x) x.begin(),x.end()
//#define rall(x) x.rbegin(),x.rend()
//#define pb push_back
//#define pii pair<int,int>
using namespace std;
inline int read(){
    int a=0;int b=1;char c=getchar();
    while(c<48||c>57){if(c=='-')b=-1;c=getchar();}
    while(c<=57&&c>=48){a*=10;a+=c-48;c=getchar();}return a*b;
}
void solve(){
    int n=read(),sum=0;
    for(int i=1;i<=n;i++){
        int x=read(),y=read(),r=read();
        sum+=abs(x)+abs(y);
    }
    if(sum>90*n){
        cout<<"bit-noob\n";
    }else {
        cout<<"buaa-noob\n";
    }
}
signed main(){
    int _=1;
//    _=read();
    while(_--)solve();
}
F 鸡数题!
结论题 卡特兰数
结果为{n,n}
公式为
0-M
i^n/(i!)/(m-i)!
代码如下

#include<bits/stdc++.h>
#define int long long
#define all(x) x.begin(),x.end()
#define rall(x) x.rbegin(),x.rend()
#define pb push_back
#define pii pair<int,int>
using namespace std;
inline int read(){
    int a=0;int b=1;char c=getchar();
    while(c<48||c>57){if(c=='-')b=-1;c=getchar();}
    while(c<=57&&c>=48){a*=10;a+=c-48;c=getchar();}return a*b;
}
const int maxn=1e5+10;
const int mod=1e9+7;
int qpow(int x,int y){
    int ans=1;
    while(y){
        if(y&1)ans=ans*x%mod;
        x=x*x%mod;
        y>>=1;
    }
    return ans;
}
int f[maxn],inv[maxn];
int getc(int x,int y){
    return f[x]*inv[y]%mod*inv[x-y]%mod;
}
void solve(){
    int n=read(),m=read();
    if(m>n){
        cout<<"0\n";
        return;
    }
    vector<int>f(n+1,1),g(n+1,1);
    for(int i=1;i<=n;i++){
        g[i]=qpow(f[i]=f[i-1]*i%mod,mod-2);
    }
    int res=0;
    for(int i=0;i<=m;i++){
        int p=qpow(i,n)*g[i]%mod*g[m-i]%mod;
        if((m-i)%2)res+=mod-p;
        else res+=p;
        res%=mod;
    }
    cout<<res<<endl;
}
signed main(){
    int _=1;
//    _=read();
    while(_--)solve();
}

H 01背包,但是bit
通过枚举当位是否存在
如果存在则按位取反 然后比该位小的则全部可取比该位大的则不取
代码如下//参考jiangly

#include<bits/stdc++.h>
#define int long long
#define all(x) x.begin(),x.end()
#define rall(x) x.rbegin(),x.rend()
#define pb push_back
#define pii pair<int,int>
using namespace std;
inline int read(){
    int a=0;int b=1;char c=getchar();
    while(c<48||c>57){if(c=='-')b=-1;c=getchar();}
    while(c<=57&&c>=48){a*=10;a+=c-48;c=getchar();}return a*b;
}
const int mod=1e9+7;
void solve(){
    int n=read(),m=read();
    vector<int>v(n),w(n);
    for(int i=0;i<n;i++)v[i]=read(),w[i]=read();
    int ans=0;
    auto check=[&](int s){
        int res=0;
        for(int i=0;i<n;i++){
            if((s&w[i])==w[i])res+=v[i];
        }
        ans=max(ans,res);
    };
    for(int i=29;i>=0;i--){
        if(m>>i&1){
            check((m^(1<<i))|((1<<i)-1));
        }
    }
    check(m);
    cout<<ans<<endl;
}
signed main(){
    int _=1;
    _=read();
    while(_--)solve();
}
大概就补到这里了 感谢观看
2024 2.12

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值