2020牛客寒假算法基础集训营6 题目及解析

传送门:2020牛客寒假算法基础集训营6

传送门:2020牛客寒假算法基础集训营1 题目及解析
传送门:2020牛客寒假算法基础集训营4 题目及解析
传送门:2020牛客寒假算法基础集训营5 题目及解析
传送门:2020牛客寒假算法基础集训营6 题目及解析

由于是个人总结向,所以有点精简,而且可能和官方的标程截然不同,当然如果有什么疑问可以留言或者私信交流。

文章目录

  • A. 配对
  • B. 图
  • C. 汉诺塔
  • D. 重排列
  • E. 立方数
  • F. 十字阵列
  • G. 括号序列
  • I. 导航系统
  • J. 签到题

A. 配对

思路:

  1. 签到题?贪心,两个数组各取前k大,保证乱搞都是这k个数最大。
  2. 然后大的加小的,最后排个序取最小的就可以了。

    代码如下:
#include
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#define ll long long
//#define ll unsigned long long
#define inf 0x3f3f3f3f
#define mod 1000000007
#define eps 1e-6
#define pi acos(-1)
#define mea (memset(a,0,sizeof(a)))
#define myit set::iterator
#define mysets multiset
#define myits multiset::iterator
#define v30 (1<<30)-1
#define all(x) (x).begin(),(x).end()
#define maxs *s.rbegin()
#define lowbit(x) (x&(-x))
#define mid ((a[k].r+a[k].l)>>1)
#define lson k<<1,l,mid
#define rson k<<1|1,mid+1,r
#define kl k<<1
#define kr k<<1|1
#define ispow(n) (n & (n - 1))
using namespace std;
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put1(){ puts("YES") ;}
void put2(){ puts("NO") ;}
void put3(){ puts("-1"); }
ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b);}
using namespace std;

const int manx=1e6+5;

ll a[manx],b[manx];
vector<ll>v1,v2,v3;
bool cmp(ll x,ll y){ return x>y;}
int main()
{
    ll n=read(),k=read();
    for(int i=1;i<=n;i++){
        a[i]=read();
    }
    for(int i=1;i<=n;i++){
        b[i]=read();
    }
    sort(a+1,a+1+n),sort(b+1,b+1+n);
    for(int i=n,j=1;j<=k;i--,j++)
        v1.push_back(a[i]),v2.push_back(b[i]);
    sort(all(v1));
    sort(all(v2),cmp);
    for(int i=0;i<v1.size();i++)
        v3.push_back(v1[i]+v2[i]);
    sort(all(v3));
    cout<<v3[0]<<endl;
    return 0;
}


B. 图

思路:

  1. 注意自环,单环,多环这三种情况。

    代码如下:
#include
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#define ll long long
//#define ll unsigned long long
#define inf 0x3f3f3f3f
#define mod 1000000007
#define eps 1e-6
#define pi acos(-1)
#define mea (memset(a,0,sizeof(a)))
#define myit set::iterator
#define mysets multiset
#define myits multiset::iterator
#define v30 (1<<30)-1
#define all(x) (x).begin(),(x).end()
#define maxs *s.rbegin()
#define lowbit(x) (x&(-x))
#define mid ((a[k].r+a[k].l)>>1)
#define lson k<<1,l,mid
#define rson k<<1|1,mid+1,r
#define kl k<<1
#define kr k<<1|1
#define ispow(n) (n & (n - 1))
using namespace std;
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put1(){ puts("YES") ;}
void put2(){ puts("NO") ;}
void put3(){ puts("-1"); }
ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b);}
using namespace std;

const int manx=1e6+5;
ll a[manx], ans[manx];
bool vis[manx];
ll now = -1;
ll dfs(ll u) {
    vis[u]=1;
    ll v=a[u];
    if(vis[v]){
        ans[u]=ans[v]+1;
        if(!ans[v]) now =v;
        return ans[u];
    }
    return ans[u]=dfs(v)+1;
}
void check(ll u, ll v) {
    ans[u]=ans[v];
    if (a[u]!= v)
        check(a[u],v);
}
int main() {
    ll n=read();
    for(int i=1;i<=n;i++) 
        a[i]=read();
    ll res=0;
    for(int i=1;i<=n;i++) {
        if(!vis[i]){
            now=-1;
            dfs(i);
            if (now!=-1) check(now, now);
        }
    }
    sort(ans+1,ans+n+1);
    cout<<ans[n]<<endl;
    return 0;
}


C. 汉诺塔

思路:

  1. Dilworth定理,最小组数等于Zi的最长下降子序列长度。
  2. 可参考这里的证明

    代码如下:
#include
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#define ll long long
//#define ll unsigned long long
#define inf 0x3f3f3f3f
#define mod 1000000007
#define eps 1e-6
#define pi acos(-1)
#define mea (memset(a,0,sizeof(a)))
#define myit set::iterator
#define mysets multiset
#define myits multiset::iterator
#define v30 (1<<30)-1
#define all(x) (x).begin(),(x).end()
#define maxs *s.rbegin()
#define lowbit(x) (x&(-x))
#define mid ((a[k].r+a[k].l)>>1)
#define lson k<<1,l,mid
#define rson k<<1|1,mid+1,r
#define kl k<<1
#define kr k<<1|1
#define ispow(n) (n & (n - 1))
using namespace std;
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put1(){ puts("YES") ;}
void put2(){ puts("NO") ;}
void put3(){ puts("-1"); }
ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b);}
using namespace std;

const int manx=1e5+5;

struct node{
    ll x,y,z;
}a[manx];
bool cmp(node a,node b){ return a.x>b.x;}
ll ans[manx],b[manx];
int main()
{
    ll n=read();
    for(int i=1;i<=n;i++)
        a[i].x=read(),a[i].y=read(),a[i].z=i;
    sort(a+1,a+1+n,cmp);
    memset(b,inf,sizeof(b));
    for(int i=1;i<=n;i++){
        ll x=lower_bound(b,b+n,a[i].y)-b;
        b[x]=a[i].y;
        ans[a[i].z]=x+1;
    }
    cout<<lower_bound(b,b+n,inf)-b<<endl;
    for(int i=1;i<=n;i++)
        cout<<ans[i]<<" ";
    cout<<endl;
    return 0;
}


D. 重排列

思路:

  1. 填坑,在b里面找有多少个比a大的。
  2. 比如现在a.1 2 3 4 b-5 6 7 8,总方案是不是4x3x2x1
  3. 放置1时有四个数可以选
  4. … 以此类推

    代码如下:
#include
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#define ll long long
//#define ll unsigned long long
#define inf 0x3f3f3f3f
#define mod 1000000007
#define eps 1e-6
#define pi acos(-1)
#define mea (memset(a,0,sizeof(a)))
#define myit set::iterator
#define mysets multiset
#define myits multiset::iterator
#define v30 (1<<30)-1
#define all(x) (x).begin(),(x).end()
#define maxs *s.rbegin()
#define lowbit(x) (x&(-x))
#define mid ((a[k].r+a[k].l)>>1)
#define lson k<<1,l,mid
#define rson k<<1|1,mid+1,r
#define kl k<<1
#define kr k<<1|1
#define ispow(n) (n & (n - 1))
using namespace std;
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put1(){ puts("YES") ;}
void put2(){ puts("NO") ;}
void put3(){ puts("-1"); }
ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b);}
using namespace std;

const int manx=1e5+5;

ll a[manx],b[manx];

int main()
{
    ll n=read();
    for(int i=1;i<=n;i++) a[i]=read();
    for(int i=1;i<=n;i++) b[i]=read();
    sort(a+1,a+1+n),sort(b+1,b+1+n);
    for(int i=1;i<=n;i++)
        if(a[i]>b[i]){
            puts("0");
            return 0;
        }
    ll ans=1;
    for(int i=1;i<=n;i++){
        ll p=upper_bound(a+1,a+1+n,b[i])-a-1;
        ans= (ans*(p-i+1))%mod;
    }
    cout<<ans<<endl;
    return 0;
}


E. 立方数

思路:

  1. 全场唯一毒瘤题,卡cout卡输出范围。
  2. 先筛选可以被整除的质数,再二分找剩下的数。

    代码如下:
#include
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#define ll long long
//#define ll unsigned long long
#define inf 0x3f3f3f3f
#define mod 1000000007
#define eps 1e-6
#define pi acos(-1)
#define mea (memset(a,0,sizeof(a)))
#define myit set::iterator
#define mysets multiset
#define myits multiset::iterator
#define v30 (1<<30)-1
#define all(x) (x).begin(),(x).end()
#define maxs *s.rbegin()
#define lowbit(x) (x&(-x))
#define mid ((a[k].r+a[k].l)>>1)
#define lson k<<1,l,mid
#define rson k<<1|1,mid+1,r
#define kl k<<1
#define kr k<<1|1
#define ispow(n) (n & (n - 1))
using namespace std;
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put1(){ puts("Yes") ;}
void put2(){ puts("No") ;}
void put3(){ puts("-1"); }
ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b);}
using namespace std;

const int manx=4e4+5;

ll prime[manx],p[manx];
bool vis[manx];
inline void doprime(){
    int cnt=0;
    for(int i=2;i<manx;i++){
        if(!vis[i]) prime[++cnt]=i,p[cnt]=i*i*i;
        for(int j=1;j<=cnt&&i*prime[j]<manx;j++){
            vis[i*prime[j]]=1;
            if(i%prime[j]==0) break;
        }
    }
}
int main()
{
    int t;  scanf("%d", &t);
    doprime();
    while(t--){
        ll n;  scanf("%lld", &n);
        ll ans=1;
        for(int i=1;i<=3500;i++){
            if(p[i]>n) break;
            while(n%p[i]==0) ans*=prime[i],n/=p[i];
            while(n%prime[i]==0) n/=prime[i];
        }
        ll l=32000,r=1000000;
        while(l<=r){
            ll m= l+ r >> 1;
            if(n>m*m*m) l=m+1;
            else r=m-1;
        }
        if(l*l*l==n) ans*=l;
       // cout<
        printf("%lld\n",ans);
    }
    return 0;
}


F. 十字阵列

思路:

  1. 用两个数组标记行列收到伤害,一个标记单体伤害即可。

    代码如下:
#include
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#define ll long long
//#define ll unsigned long long
#define inf 0x3f3f3f3f
#define mod 1000000007
#define eps 1e-6
#define pi acos(-1)
#define mea (memset(a,0,sizeof(a)))
#define myit set::iterator
#define mysets multiset
#define myits multiset::iterator
#define v30 (1<<30)-1
#define all(x) (x).begin(),(x).end()
#define maxs *s.rbegin()
#define lowbit(x) (x&(-x))
#define mid ((a[k].r+a[k].l)>>1)
#define lson k<<1,l,mid
#define rson k<<1|1,mid+1,r
#define kl k<<1
#define kr k<<1|1
#define ispow(n) (n & (n - 1))
using namespace std;
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put1(){ puts("YES") ;}
void put2(){ puts("NO") ;}
void put3(){ puts("-1"); }
ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b);}
using namespace std;

const int manx=2500;

ll w1[manx],w2[manx],w[manx][manx];

int main()
{
    ll n=read(),m=read(),k=read();
    for(int i=1;i<=k;i++){
        ll x=read(),y=read(),z=read();
        w1[x]+=z;
        w2[y]+=z;
        w[x][y]+=z;
    }
    ll ans=0;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            ans+= (((w1[i]+w2[j]-w[i][j])%mod)*(i+j))%mod;
            ans%=mod;
        }
    }
    cout<<ans%mod<<endl;
    return 0;
}


G. 括号序列

思路:

  1. 用 l 和 r 来标记非法的括号。

    代码如下:
#include
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#define ll long long
//#define ll unsigned long long
#define inf 0x3f3f3f3f
#define mod 1000000007
#define eps 1e-6
#define pi acos(-1)
#define mea (memset(a,0,sizeof(a)))
#define myit set::iterator
#define mysets multiset
#define myits multiset::iterator
#define v30 (1<<30)-1
#define all(x) (x).begin(),(x).end()
#define maxs *s.rbegin()
#define lowbit(x) (x&(-x))
#define mid ((a[k].r+a[k].l)>>1)
#define lson k<<1,l,mid
#define rson k<<1|1,mid+1,r
#define kl k<<1
#define kr k<<1|1
#define ispow(n) (n & (n - 1))
using namespace std;
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put1(){ puts("YES") ;}
void put2(){ puts("NO") ;}
void put3(){ puts("-1"); }
ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b);}
using namespace std;

const int manx=1e6+5;



int main()
{
    ll p=read(),t=1;
    while(p--){
        ll n=read();
        string s;
        cin>>s;
        ll l=0,r=0;
        for(int i=0;i<s.size();i++){
            if(s[i]=='(') l++;
            else if(s[i]==')'){
                if(l) l--;
                else r++;
            }
        }
        if(l) r+=l;
        cout<<r<<endl;
    }
    return 0;
}


I. 导航系统

思路:

  1. 用已知得边建最小生成树,然后更新边与边的距离,看是否有出入。

    代码如下:
#include
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#define ll long long
//#define ll unsigned long long
#define inf 0x3f3f3f3f
#define mod 1000000007
#define eps 1e-6
#define pi acos(-1)
#define mea (memset(a,0,sizeof(a)))
#define myit set::iterator
#define mysets multiset
#define myits multiset::iterator
#define v30 (1<<30)-1
#define all(x) (x).begin(),(x).end()
#define maxs *s.rbegin()
#define lowbit(x) (x&(-x))
#define mid ((a[k].r+a[k].l)>>1)
#define lson k<<1,l,mid
#define rson k<<1|1,mid+1,r
#define kl k<<1
#define kr k<<1|1
#define ispow(n) (n & (n - 1))
using namespace std;
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put1(){ puts("Yes") ;}
void put2(){ puts("No") ;}
void put3(){ puts("-1"); }
ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b);}
using namespace std;

const int manx=500+5;

ll n,k;
ll f[manx],d[manx][manx],q[manx][manx],ans[manx];
struct node{
    ll u,v,w;
}a[manx*manx];
bool cmp(node a , node b){ return a.w<b.w; }
int find(int x){
    if(f[x]==x) return x;
    return f[x]=find(f[x]);
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            d[i][j]=read();
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(d[i][j]!=d[j][i]){
                put2();
                return 0;
            }
            else a[++k].u=i,a[k].v=j,a[k].w=d[i][j];
    sort(a+1,a+1+k,cmp);
    memset(q,inf,sizeof(q));
    for(int i=1;i<=n;i++) f[i]=i,q[i][i]=0;
    ll index=1;
    for(int i=1;i<=k;i++){
        ll u=find(a[i].u),v=find(a[i].v);
        if(u==v) continue;
        index++;
        ans[index]=a[i].w;
        f[u]=v;
        q[a[i].u][a[i].v]=q[a[i].v][a[i].u]=a[i].w;
        if(index==n) break;
    }
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                q[i][j]=min(q[i][j],q[i][k]+q[k][j]);
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
            if(q[i][j]!=d[i][j]){
                put2();
                return 0;
            }
    put1();
    for(int i=2;i<=n;i++)
        cout<<ans[i]<<endl;
    return 0;
}


J. 签到题

思路:

  1. 列三个方程,记得解出来记得判断是否边长为正数。

    代码如下:
#include
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#define ll long long
//#define ll unsigned long long
#define inf 0x3f3f3f3f
#define mod 1000000007
#define eps 1e-6
#define pi acos(-1)
#define mea (memset(a,0,sizeof(a)))
#define myit set::iterator
#define mysets multiset
#define myits multiset::iterator
#define v30 (1<<30)-1
#define all(x) (x).begin(),(x).end()
#define maxs *s.rbegin()
#define lowbit(x) (x&(-x))
#define mid ((a[k].r+a[k].l)>>1)
#define lson k<<1,l,mid
#define rson k<<1|1,mid+1,r
#define kl k<<1
#define kr k<<1|1
#define ispow(n) (n & (n - 1))
using namespace std;
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put1(){ puts("YES") ;}
void put2(){ puts("NO") ;}
void put3(){ puts("-1"); }
ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b);}
using namespace std;

const int manx=1e6+5;
int main()
{
    ll a=read(),b=read(),c=read();
    if(a>b) swap(a,b);
    if(a>c) swap(a,c);
    if(b>c) swap(b,c);
  //  cout<
    if(a+b<=c) puts("wtnl");
    else{
        double x=(a+c-b)*1.0/2;
        double y=a*1.0-x;
        double z=c*1.0-x;
        if(x>0&&y>0&&z>0){
            if(x>y) swap(x,y);
            if(x>z) swap(x,z);
            if(y>z) swap(y,z);
            puts("Yes");
            printf("%.2lf %.2lf %.2lf",x,y,z);
        }
        else puts("No");
    }
    return 0;
}


你可能感兴趣的:(acm)