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

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

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

A. 欧几里得

思路:

  1. 签到题吧,随便打表看n=0-5的情况,可以明显发现跟fib有关。

    代码如下:
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#define ll long long
//#define ll unsigned long long
#define R register int
#define inf 0x3f3f3f3f
#define mod 1000000007
#define eps 1e-6
#define pi acos(-1)
#define mea (memset(a,0,sizeof(a)))
#define myit set<ll>::iterator
#define myits  multiset<ll>::iterator
#define v30 (1<<30)-1
#define all(x) (x).begin(),(x).end()
#define maxs *s.rbegin()
#define fi first
#define se second
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 ans=0;
// ll gcd(ll a,ll b){ ans++;return b==0?a:gcd(b,a%b);}
using namespace std;

const int manx=2e6+5;

ll a[manx],b[manx];;
int main()
{
    a[0]=1,a[1]=2,a[2]=3;
    b[0]=0,b[1]=1,b[2]=2;
    for(int i=3;i<=80;i++)
        a[i]=a[i-1]+a[i-2],b[i]=b[i-1]+b[i-2];
    ll p=read();
    while(p--){
        ll n=read();
        cout<<a[n]+b[n]<<endl;
    }
    return 0;
}


B. 括号序列

思路:

  1. 签到题,左的入栈右的匹配,但浪费了我不少时间,注意最后判空。

    代码如下:
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#define ll long long
//#define ll unsigned long long
#define R register int
#define inf 0x3f3f3f3f
#define mod 1000000007
#define eps 1e-6
#define pi acos(-1)
#define mea (memset(a,0,sizeof(a)))
#define myit set<ll>::iterator
#define myits  multiset<ll>::iterator
#define v30 (1<<30)-1
#define all(x) (x).begin(),(x).end()
#define maxs *s.rbegin()
#define fi first
#define se second
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 ans=0;
ll gcd(ll a,ll b){ ans++;return b==0?a:gcd(b,a%b);}
using namespace std;
 
const int manx=2e6+5;
char a[manx];
 
int main()
{
    string s;
    cin>>s;
    ll len=0;
    for(int i=1;i<=s.size();i++){
        char c=s[i-1];
        if(c=='{'||c=='('||c=='[')
            a[++len]=c;
        else if(len==0){
            put2();
            return 0;
        }
        else if(c=='}'){
            if(a[len]!='{'){
                put2();
                return 0;
            }
            else len--;
        }
        else if(c==')'){
            if(a[len]!='('){
                put2();
                return 0;
            }
            else len--;
        }
        else if(c==']'){
            if(a[len]!='['){
                put2();
                return 0;
            }
            else len--;
        }
    }
    if(len==0) put1();
    else put2();
    return 0;
}


C. hanayo和米饭

思路:

  1. 签到题,线段树+暴力,线段树只用查询就可以了。

代码如下:

#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(0)
//#define ll long long
#define ll unsigned long long
#define R register int
#define inf 0x3f3f3f3f
#define mod 998244353
#define eps 1e-6
#define pi acos(-1)
#define mea (memset(a,0,sizeof(a)))
#define myit set<ll>::iterator
#define myits  multiset<ll>::iterator
#define v30 (1<<30)-1
#define all(x) (x).begin(),(x).end()
#define maxs *s.rbegin()
#define fi first
#define se second
#define mid ((tree[k].l+tree[k].r)>>1)
#define lson k<<1,l,mid
#define rson k<<1|1,mid+1,r
#define kl k<<1
#define kr k<<1|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=2e5+10;
 
ll n,l,r,w,x,ans;
ll aa[manx];
 
struct node{
    ll l,r,w,f;
}tree[4*manx];
 
inline void build(ll k, ll l, ll r)
{
    tree[k].l=l,tree[k].r=r;
    if(tree[k].l==tree[k].r){
        tree[k].w=aa[l];
        return ;
    }
    build(lson);
    build(rson);
    tree[k].w=(tree[kl].w*tree[kr].w)%mod;
}
 
inline void down(ll k)
{
    tree[kl].f+=tree[k].f;
    tree[kr].f+=tree[k].f;
    tree[kl].w+=tree[k].f*(tree[kl].r-tree[kl].l+1);
    tree[kr].w+=tree[k].f*(tree[kr].r-tree[kl].l+1);
    tree[k].f=0;
}
inline void find2(ll k)
{
    if(tree[k].l>=l&&tree[k].r<=r){
        ans*=tree[k].w;
        ans%=mod;
        return ;
    }
    if(tree[k].f) down(k);
    if(l<=mid) find2(kl);
    if(r>mid) find2(kr);
}
 
int main()
{
    ll n=read(),k=read();
    for(int i=1;i<=n;i++)
        aa[i]=read();
    build(1,1,n);
    ll    myans=0;
    for(int i=k;i<=n;i++){
        ans=1;
        l=i-k+1,r=i;
        find2(1);
        myans=max(ans%mod,myans);
        myans%=mod;
       // cout<<myans<<" "<<ans<<endl;
    }
    cout<<myans%mod<<endl;
    return 0;
}


D. 子段异或

思路:

  1. 签到题,用一个map记录异或的路径,当走到重复点的时候,这个点对答案的贡献为 这个点在之前出现的次数。

    代码如下:
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#define ll long long
//#define ll unsigned long long
#define R register int
#define inf 0x3f3f3f3f
#define mod 1000000007
#define eps 1e-6
#define pi acos(-1)
#define mea (memset(a,0,sizeof(a)))
#define myit set<ll>::iterator
#define myits  multiset<ll>::iterator
#define v30 (1<<30)-1
#define all(x) (x).begin(),(x).end()
#define maxs *s.rbegin()
#define fi first
#define se second
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=2e6+5;

ll a[manx],b[manx];
map<ll,ll>mp;
int main()
{
    ll n=read();
    for(int i=1;i<=n;i++){
        a[i]=read();
    }
    ll ans=0;
    ll x=0;
    mp[0]=1;
    for(int i=1;i<=n;i++){
        x=x^a[i];
        if(mp[x]) ans+=mp[x];
        mp[x]++;
    }
    cout<<ans<<endl;
    return 0;
}


E. 最小表达式

思路:

  1. 是我写的最久的一道,做的时候以为是dfs,做到一半才想起是贪心模拟题。
  2. 要使结果最小,肯定要把小的数字放前面,先把数字个数%(加号个数+1)的余数分配好,其余的暴力模拟就可以了。

    代码如下:
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#define ll long long
//#define ll unsigned long long
#define R register int
#define inf 0x3f3f3f3f
#define mod 1000000007
#define eps 1e-6
#define pi acos(-1)
#define mea (memset(a,0,sizeof(a)))
#define myit set<ll>::iterator
#define myits  multiset<ll>::iterator
#define v30 (1<<30)-1
#define all(x) (x).begin(),(x).end()
#define maxs *s.rbegin()
#define fi first
#define se second
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 = 5e5 + 5;


string add(string a,string b)
{
	string c;
	string d="0";
	long int kmin,kmax,i;
	reverse(all(a));
	reverse(all(b));
	if(a.length()>b.length()) {kmin=b.length();kmax=a.length();c=a;}
	else {kmin=a.length();kmax=b.length();c=b;}
	c.insert(c.length(),d);
	for(i=0;i<kmin;i++)
	{
		if(a.at(i)>=48&&a.at(i)<=57) a.at(i)-=48;
		if(a.at(i)>=97&&a.at(i)<=122) a.at(i)-=87;
		if(b.at(i)>=48&&b.at(i)<=57) b.at(i)-=48;
		if(b.at(i)>=97&&b.at(i)<=122) b.at(i)-=87;
		c.at(i)=a.at(i)+b.at(i);
	}
	for(i=kmin;i<kmax+1;i++)
	{
		if(c.at(i)>=48&&c.at(i)<=57) c.at(i)-=48;
		if(c.at(i)>=97&&c.at(i)<=122) c.at(i)-=87;
	}
	for(i=0;i<kmax;i++)
	{
		if(c.at(i)>=10)
		{
			c.at(i+1)+=c.at(i)/10;
			c.at(i)=c.at(i)%10;
		}
	}
	if(c.at(kmax)==0)
	{
		c.erase(kmax,kmax+1);
	}
	for(i=0;i<c.length();i++)
	{
		if(c.at(i)>=10) c.at(i)+=87;
		if(c.at(i)<10) c.at(i)+=48;
	}
	reverse(all(c));
	return c;
}
int main()
{
    string s;
    cin>>s;
    sort(all(s));
   cout<<s<<endl;
    ll cnt=0;
    for(int i=0;i<s.size();i++)
        if(s[i]=='+') cnt++;
        else break;
    if(cnt==0) cout<<s<<endl;
    else{
        s=s.substr(cnt);
        cnt++;
        int k=s.size()%(cnt);
        string a[cnt];
        int index=0;
        for(int i=0;i<k;i++){
            a[index]+=s[i];
            index++;
            index%=(cnt);
        }
        index=0;
        s=s.substr(k);
       // cout<<s<<endl;
        for(int i=0;i<s.size();i++){
            a[index]+=s[i];
            index++;
            index%=cnt;
        }
        string ans="0";
        for(int i=0;i<cnt;i++){
         //    cout<<a[i]<<endl;
          //  reverse(all(a[i]));
          //  reverse(all(ans));
            ans=add(a[i],ans);
        }
        cout<<ans<<endl;
    }
    return 0;
}


F. 树上博弈

思路:

  1. 当先手与后手距离为偶数必胜,所以这题可以转化为求树上偶数长度的路径数。
  2. dp[i][0]表示子树到i结点的偶数路径数,1则为偶。
  3. 那么ans=dp[父][0]*dp[子][1]+dp[父][1]*dp[子][0]。
  4. 注意最后ans*2,因为位置可以互换。

    代码如下:
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#define ll long long
//#define ll unsigned long long
#define R register int
#define inf 0x3f3f3f3f
#define mod 1000000007
#define eps 1e-6
#define pi acos(-1)
#define mea (memset(a,0,sizeof(a)))
#define myit set<ll>::iterator
#define myits  multiset<ll>::iterator
#define v30 (1<<30)-1
#define all(x) (x).begin(),(x).end()
#define maxs *s.rbegin()
#define fi first
#define se second
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 maxn = 2e6+ 5;
ll dp[maxn][2], ans = 0;;
vector<int> vt[maxn];
void dfs(int u, int f)
{
    dp[u][0]=1;
    dp[u][1]=0;
    for(int i =0;i<vt[u].size();i++){
        int to=vt[u][i];
        if(to==f) continue;
        dfs(to,u);
        ans+=dp[u][0]*dp[to][1];
        ans+=dp[u][1]*dp[to][0];
        dp[u][0]+=dp[to][1];
        dp[u][1]+=dp[to][0];
    }
}
int main()
{
    ll n=read(),x;
    for(int i = 1; i < n; i++){
        x=read();
        vt[x].push_back(i+1);
        vt[i+1].push_back(x);
    }
    ans=0;
    dfs(1,-1);
    ans=ans<<1;
    cout<<ans<<endl;
    return 0;
}


G. 音乐鉴赏

思路:

  1. 直接化整为零,把n个人当成1个人,求出平均的平时成绩。
  2. 而90的期末成绩要前10%,就可以=90*0.9=81。
  3. 设期末成绩占比为x,可得方程:
  4. 81x+ans(1-x)=90 , 解得x 。

    代码如下:
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#define ll long long
//#define ll unsigned long long
#define R register int
#define inf 0x3f3f3f3f
#define mod 1000000007
#define eps 1e-6
#define pi acos(-1)
#define mea (memset(a,0,sizeof(a)))
#define myit set<ll>::iterator
#define myits  multiset<ll>::iterator
#define v30 (1<<30)-1
#define all(x) (x).begin(),(x).end()
#define maxs *s.rbegin()
#define fi first
#define se second
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];
double ans=0;
int main()
{
    ll n=read();
    for(int i=0;i<n;i++){
        a[i]=read();
        ans=ans+a[i];
    }
    ans=ans*1.0/n;
    printf("%.2lf",(90-ans)*1.0/(81-ans)*100);
    cout<<"%";
    return 0;
}


H. 坐火车

思路:

  1. 用树状数组维护颜色的前缀和,再用两个数组,一个维护前缀颜色,一个维护后缀颜色,每次计算的时候要减去当前颜色的后缀suf[col[i]]–,然后计算完要加上当前颜色的前缀pre[col[i]]++。

    代码如下:
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#define ll long long
//#define ll unsigned long long
#define R register int
#define inf 0x3f3f3f3f
#define mod 1000000007
#define eps 1e-6
#define pi acos(-1)
#define mea (memset(a,0,sizeof(a)))
#define myit set<ll>::iterator
#define myits  multiset<ll>::iterator
#define v30 (1<<30)-1
#define all(x) (x).begin(),(x).end()
#define maxs *s.rbegin()
#define fi first
#define se second
#define lowbit(x) (x&(-x))
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=5e5+10;

ll col[manx],l[manx],r[manx];
ll pre[manx],suf[manx],ans[manx];
ll n;
void add(ll x,ll val){
    while(x<=n){
        ans[x]+=val;
        x+=lowbit(x);
    }
}
ll query(ll x){
    ll res=0;
    while(x){
        res+=ans[x];
        x-=lowbit(x);
    }
    return res;
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++)
        col[i]=read(),l[i]=read(),r[i]=read(),suf[col[i]]++;
    for(int i=1;i<=n;i++){
        suf[col[i]]--;
        add(col[i],-pre[col[i]]);
        cout<<query(r[i])-query(l[i]-1)<<" ";
        pre[col[i]]++;
        add(col[i],suf[col[i]]);
    }
    return 0;
}


I. 匹配星星

思路:

  1. 先对x排序,这样保证操作的时候x永远大于候选集合的x,然后看z,视情况操作,如果为0则放进候选的集合,如果是1就在候选集合里面选择小于自己且在集合里面y最大的那个元素,保证最优。

    代码如下:
#include<bits/stdc++.h>
#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<ll>::iterator
#define mysets multiset<ll>
#define myits multiset<ll>::iterator
#define v30 (1<<30)-1
#define all(x) (x).begin(),(x).end()
#define maxs *s.rbegin()
#define fi first
#define se second
#define lowbit(x) (x&(-x))
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+10;

mysets s;
struct node{
    ll x,y,z;
}a[manx];
bool cmp(node a, node b){
    if(a.x==b.x) return a.z>b.z;
    else return a.x<b.x;
}
int main()
{
    ll n=read();
    for(int i=1;i<=n;i++)
        a[i].x=read(),a[i].y=read(),a[i].z=read();
    sort(a+1,a+1+n,cmp);
    ll ans=0;
    myits it;
    for(int i=1;i<=n;i++){
        if(a[i].z){
            it=s.lower_bound(a[i].y);
            if(it!=s.begin()){
                --it;
                ans++;
                s.erase(it);
            }
        }
        else s.insert(a[i].y);
    }
    cout<<ans<<endl;
    return 0;
}


发布了61 篇原创文章 · 获赞 23 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/JiangHxin/article/details/104272158
今日推荐