牛客小白月赛23

牛客小白月赛23 

A. 膜法记录

和我签订契约成为魔法少女吧!

题意:n行m列网格中分布着敌人,可以进行a次行blast和b次列blast,问能否全歼敌人 。(T≤105,n≤5,m≤105或T=1,n≤20,m≤105

思路:n比较小,枚举每行是否选取即可。

#include <bits/stdc++.h>
using namespace std;
const int M=1e5+100;
int n,m,a,b;
char Mp[10][M];
bool Biu[10],All_dead;
bool OK(){
    set<int> col;
    for(int i=1;i<=n;i++){
        if(Biu[i]) continue;
        for(int j=1;j<=m;j++)
            if(Mp[i][j]=='*') col.insert(j);
    }
    return b>=col.size();
}
void DFS(int Row,int Biu_num){
    if(Row>n+1||Biu_num>a) return;
    if(OK()){All_dead=true;return;}
    Biu[Row]=true;
    DFS(Row+1,Biu_num+1);
    Biu[Row]=false;
    DFS(Row+1,Biu_num);
}
void solve(){
    All_dead=false;
    fill(Biu,Biu+10,false);
    cin>>n>>m>>a>>b;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            cin>>Mp[i][j];
    DFS(1,0);
    cout<<(All_dead?"yes":"no")<<"\n";
}
int main()
{
    int t;cin>>t;
    while(t--)
        solve();
    return 0;
}
View Code

B. 阶乘

题意:共T次询问,每次询问给定一个正整数p,求阶乘是p的倍数的最小正整数n。(T≤103,p≤109

思路:分解质因数,存储每个质因数的个数,将重复的质因数分配到其倍数中。

Tips:p可能为109规模的质数,散列数组一方面内存利用率较低,一方面开不到这个大小,所以使用map存储。取质因数取到根号n即可,注意最后将p也存起来。

#include <bits/stdc++.h>
using namespace std;
void solve(){
    int p;cin>>p;
    map<int,int> _map;
    for(int i=2;i*i<=p;i++)
        while(p%i==0)
            ++_map[i],p/=i;
    ++_map[p];
    int ans=1;
    for(auto &i:_map){
        int base=i.first,num=i.second;
        for(int j=1;num>0;j++){
            int now=j*base;
            ans=max(ans,now);
            while(num>0&&now%base==0)
                now/=base,--num;
        }
    }
    cout<<ans<<"\n";
}
int main()
{
    int t;cin>>t;
    while(t--)
        solve();
    return 0;
}
View Code

C. 完全图

题意:n点完全图去掉m边后的最大连通分量。(T≤104,1≤n≤1018,1≤m≤1018

思路:逐点去除,第一个点需要n-1条边,第二个点需要n-2条边,求得去掉n个点需要的边与m比较即可。由于数据比较大,所以需要二分查找。

Tips:递推公式的中间值会大于long long,可以将不等式变换到long long运算的范围。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
    int t;cin>>t;
    while(t--){
        ll n,m;cin>>n>>m;
        ll l=0,r=n-1;
        while(l<r){
            ll mid=(l+r+1)>>1;//+1是为了防止l=r-1时的不断循环
            if(2*n-mid-1<=2*m/mid) l=mid;
            else r=mid-1;
        }
        cout<<l+1<<"\n";
    }
    return 0;
}
View Code

E. A+B问题

题意:A和B都在32位有符号整数能存储的范围内,现在已知二者的和为c,问有多少种可能的输入数据。

思路:很有趣的一道题,从int的底层存储考虑,每个32bit都会对应一个和为特定值的32bit,所以答案始终是4294967296。

#include <bits/stdc++.h>
using namespace std;
int main()
{
    cout<<4294967296;
    return 0;
}
View Code

G. 树上求和

题意:n点n-1边树,为每个边赋权值,使得任意两点间路径的权值和的和最小。

思路:每个边左右点的个数之积即为该边的使用次数,将积从大到小依次赋权即可。

#include <bits/stdc++.h>
using namespace std;
const int M=1e5+100;
int n;
vector<int> e[M];
vector<long long> v;
int dfs(int u,int p){
    int sum=1;
    for(int v:e[u])
        if(v!=p)
            sum+=dfs(v,u);
    v.push_back(1LL*sum*(n-sum));
    return sum;
}
int main()
{
    cin>>n;
    for(int i=0;i<n-1;i++){
        int u,v;cin>>u>>v;
        --u,--v;
        e[u].push_back(v);
        e[v].push_back(u);
    }
    dfs(0,-1);
    sort(v.begin(),v.end(),greater<long long>());
    long long sum=0,num=1;
    for(auto i:v) sum+=i*num++;
    cout<<sum<<"\n";
    return 0;
}
View Code

H. 奇怪的背包问题增加了

题意:给你一些2的幂次方,问能否凑出230,并输出选取情况。(T≤105,1≤m≤105,Σm≤105,0≤ki<30)

思路:若当前幂次个数足够使用则选取所需,否则选取全部并继续向低幂次寻找。

开始时用递归写的,之后简化成了非递归,前者较易实现,后者较为简洁。

#include <bits/stdc++.h>
using namespace std;
const int M=1e5+100;
int Bit[32],ans[M];
vector<int> pos[32];
bool flag;
void need(int bit,int num){
    if(bit==-1){
        flag=false;
        return;
    }
    if(Bit[bit]<num){
        for(int i:pos[bit])
            ans[i]=1;
        need(bit-1,2*(num-Bit[bit]));
    }else{
        for(int i=0;i<num;i++)
            ans[pos[bit][i]]=1;
    }
}
void init(){
    flag=true;
    for(auto &v:pos) v.clear();
    fill(Bit,Bit+32,0);
    fill(ans,ans+M,0);
}
void solve(){
    init();
    int n;cin>>n;
    for(int i=0;i<n;i++){
        int t;cin>>t;
        ++Bit[t];
        pos[t].push_back(i);
    }
    need(30,1);
    if(flag) for(int i=0;i<n;i++) cout<<ans[i]<<(i==n-1?"\n":"");
    else cout<<"impossible\n";
}
int main()
{
    int t;cin>>t;
    while(t--)
        solve();
    return 0;
}
View Code
#include <bits/stdc++.h>
using namespace std;
const int M=1e5+100;
void solve(){
    int Bit[32]={0},ans[M]={0};
    vector<int> pos[32];
    int n;cin>>n;
    for(int i=0;i<n;i++){
        int t;cin>>t;
        ++Bit[t];
        pos[t].push_back(i);
    }
    int bit=30,need=1;
    while(bit!=-1&&Bit[bit]<need){
        need=2*(need-Bit[bit]);
        for(int i:pos[bit]) ans[i]=1;
        --bit;
    }
    if(bit!=-1){
        for(int i=0;i<need;i++) ans[pos[bit][i]]=1;
        for(int i=0;i<n;i++) cout<<ans[i]<<(i==n-1?"\n":"");
    }
    else cout<<"impossible\n";
}
int main()
{
    int t;cin>>t;
    while(t--)
        solve();
    return 0;
}
View Code

I. 寻找子串

题意:字符串的子串是指字符串中连续的一段,给定字符串s,请你找出字典序最大的子串。(|s|≤103

思路:先找到字典序最大的字母,然后以该字母为首截取子串,取最大串即可。

#include <bits/stdc++.h>
using namespace std;
int main()
{
    string s;cin>>s;
    char c=*max_element(s.begin(),s.end());
    string ans;
    for(int i=0;i<s.size();i++)
        if(s[i]==c)
            ans=max(ans,s.substr(i));
    cout<<ans;
    return 0;
}
View Code

J. 最大的差

题意:给定n个数字,请你从中选出两个数字,使得这两个数字的差尽量大,输出这个最大的差。(2≤n≤105,|ai|≤105

思路:签到题。

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int n;cin>>n;
    int a[n];for(int &i:a) cin>>i;
    sort(a,a+n);
    cout<<a[n-1]-a[0];
    return 0;
}
View Code

 

posted @ 2020-03-21 23:30  Kanoon  阅读(516)  评论(4编辑  收藏  举报