牛客-中南林业科技大学第十一届程序设计大赛

42 篇文章 0 订阅
33 篇文章 0 订阅

牛客-中南林业科技大学第十一届程序设计大赛


A-译码

思路:用string a[]数组来保存编码所对于的字符串,对于所给的数字串将其每5个转换为编码即可。

Code A:

#include<iostream>
using namespace std;

const int MAX_N=20005;
const int MAX_M=1005;
int T,n,m;
string a[MAX_N];

int main()
{
	ios::sync_with_stdio(false);
	int t=0;
	for(int i=0;i<26;++i)
		for(int j=0;j<26;++j)
			for(int k=0;k<26;++k)
			{
				a[t]=char(i+'a');
				a[t]+=char(j+'a');
				a[t++]+=char(k+'a');
			}
	cin>>T;
	string str;
	while(T--){
		cin>>n>>str;
		for(int i=0;i<n;)
		{
			int t=0;
			for(int j=0;j<5;++j)
				t=t*10+(str[i++]-'0');
			cout<<a[t];
		}
		cout<<endl;
	}
	return 0;
}


B-Fence Repair

思路:直接暴力。。。

Code B:

#include<iostream>
#include<cstring>
using namespace std;

const int MAX_N=1005;
int n;
int a[MAX_N];

int main()
{
	ios::sync_with_stdio(false);
	while(cin>>n){
		memset(a,0,sizeof(a));
		for(int i=0;i<n;++i)
			cin>>a[i];
		int ans=0;
		for(int i=0;i<n;++i)
			for(int j=i+1;j<n;++j)
				if(a[i]*2==a[j])	ans++;
		cout<<ans<<endl;
	}
	
	return 0;
}


C-有趣的二进制

思路:这题交了15遍。。。按照其原码到补码的转换过程写,开始是由于没有用 long long 导致错误,改了后又是段错误,交了几遍发现是由于位运算搞的鬼,把 n&1改成n%2,n>>=1改成n/=2就过了。。。

Code C:

#include<iostream>
#include<cstring>
using namespace std;
typedef long long LL;

LL n;
LL a[105];

int main()
{
	ios::sync_with_stdio(false);
	while(cin>>n){
		memset(a,0,sizeof(a));
		int t=0;
		LL ans=0;
		if(n<0){
			ans=1;
			n=-n;
		} 
		while(n){
			a[t++]=n%2;
			n/=2;
		}
		t=64;
		if(ans){
			for(int i=0;i<t-1;++i)
				if(a[i])	a[i]=0;
				else	a[i]=1;
			int p=1;
			for(int i=0;i<t-1;++i)
			{
				a[i]=a[i]+p;
				p=a[i]/2;
				a[i]=a[i]%2;
			} 
		}
		for(int i=0;i<t-1;++i)
			if(a[i])	ans++;
		cout<<ans<<endl; 
	}
	
	return 0;
}

看大佬的代码还可以这样做,佩服佩服

Code C:

#include<iostream>
using namespace std;
unsigned long long n;
int main(){
    while(cin>>n){
        long long ans=0;
        while(n){
            if(n&1) ans++;
            n>>=1;
        }
        cout<<ans<<endl;
    }
    return 0;
}


D-有趣的数字

思路:暴力出前20个找规律即可,还是很好找规律的

Code D:

#include<iostream>
#include<cmath>
using namespace std;
typedef long long LL;

LL n;

int main()
{
	ios::sync_with_stdio(false);
	while(cin>>n){
		LL s=sqrt(n);
		cout<<n-s<<endl;
	}
	
	return 0;
}


E-邝博士的问题

思路: 分别计算出 向下和向上取整的金银铜牌的数量a,b,c,aa,bb,cc,则金牌的变换数即为aa-a,银牌为aa+bb-a-b,铜牌为aa+bb+cc-a-b-c;

Code E:

#include<iostream>
using namespace std;
typedef long long LL;

LL n;

int main()
{
	ios::sync_with_stdio(false);
	while(cin>>n){
		LL a,b,c;
		LL aa,bb,cc;
		a=n/10;	aa=(n+9)/10;
		b=n/5;	bb=(n+4)/5;
		c=n*3/10;	cc=(n*3+9)/10;
		LL s1,s2,s3;
		s1=aa-a;	s2=aa+bb-a-b;	s3=aa+bb+cc-a-b-c;
		cout<<s1<<" "<<s2<<" "<<s3<<endl;
	} 
	
	return 0;
}


F-新田忌赛马

思路一:贪心+二分,先赢得价值大的马,则将齐威王的马按照其价值按从大到小排序,对于相同价值的按照速度由小到大排序。在将田忌的马按速度由小到大排序,遍历齐威王的马,每次用二分查找到最小比齐威王马速度大的田忌的马,用 boo[i]标记已经比赛过的马,向后找到一个没有标记过马比赛即可

思路二:贪心+优先队列, 将齐威王和田忌的马分别按照其速度按从大到小排序,遍历田忌的马d[i],将所有齐威王的速度比d[i]小的马放入优先队列中,每次取队列中最大价值,这样所有没有加入队列和队列中剩余的都是田忌马要输的,再减去其价值即可。

Code F 1:

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

struct node{
	int x;
	int w;
	bool operator<(const node &p)const{
		if(w==p.w){
			return x<p.x;
		}else	return w>p.w;
	}
};
const int MAX_N=1005;
int n,T;
node a[MAX_N];
int d[MAX_N];
bool boo[MAX_N];

int main()
{
	ios::sync_with_stdio(false);
	cin>>T;
	while(T--){
		memset(boo,0,sizeof(boo));
		cin>>n;
		for(int i=0;i<n;++i)
			cin>>a[i].x;
		for(int i=0;i<n;++i)
			cin>>a[i].w;
		for(int i=0;i<n;++i)
			cin>>d[i];
		sort(a,a+n);
		sort(d,d+n);
		int ans=0;
		for(int i=0;i<n;++i)
		{
			int k=lower_bound(d,d+n,a[i].x+1)-d;
			bool p=false;
			for(int j=k;j<n;++j)
				if(boo[j]==false){
					p=true;
					boo[j]=true;
					ans+=a[i].w;
					break;
				}
			if(p==false)	ans-=a[i].w;
		}
		cout<<ans<<endl;
	} 
	
	return 0;
}

Code F 2:

#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;

struct node{
	int x;
	int w;
	bool operator<(const node &p)const{
		return x<p.x;
	}
};
const int MAX_N=1005;
int n,T;
node a[MAX_N];
int d[MAX_N];

int main()
{
	ios::sync_with_stdio(false);
	cin>>T;
	while(T--){
		cin>>n;
		for(int i=0;i<n;++i)
			cin>>a[i].x;
		for(int i=0;i<n;++i)
			cin>>a[i].w;
		for(int i=0;i<n;++i)
			cin>>d[i];
		sort(a,a+n);
		sort(d,d+n);
		priority_queue<int> Q;
		int ans=0,k=0;
		for(int i=0;i<n;++i)
		{
			while(k<n&&a[k].x<d[i]){
				Q.push(a[k++].w);
			}
			if(!Q.empty()){
				ans+=Q.top();	Q.pop();
			}
		}
		while(!Q.empty()){
			ans-=Q.top();	Q.pop();
		}
		while(k<n){
			ans-=a[k++].w;
		}
		cout<<ans<<endl;
	} 
	
	return 0;
}


G-组合游戏

思路:贪心,先合并长度最小的两块木板,可以用优先队列来维护最小长度。

Code G:

#include<iostream>
#include<queue>
using namespace std;

int n;

int main()
{
	ios::sync_with_stdio(false);
	while(cin>>n){
		priority_queue<int,vector<int>,greater<int> > Q;
		for(int i=0,x;i<n;++i)
		{
			cin>>x;
			Q.push(x);
		}
		int ans=0,t1,t2;
		while(Q.size()>1){
			t1=Q.top();	Q.pop();
			t2=Q.top();	Q.pop();
			ans+=t1+t2;
			Q.push(t1+t2);
		}
		cout<<ans<<endl;
	}
	
	return 0;
}


H-渴望力量吗

思路: 力量太弱。。。先挖个坑,以后填上QAQ

恩,这题我一段代码改了无数遍,结果TM是多组数据的问题,我TM。。。 (╯°Д°)╯( ┻━┻再特么的掀一次

  恩,我平复下心情。。。

这题是 排序+二分, 由于求 区间[l,r]中为x个个数,因此可以用结构体 node{ int x;int id;} a[] 存元素的值和下标, 对其按照先x由小到大排序,再id由小到大排序,这样 对于每次询问 l,r,x,则只要找到 node{x,l}和 {x,r}在 a[]中的位置下标相减即可。

Code H:

#include<iostream>
#include<algorithm>
using namespace std;

struct node{
	int x;
	int id;
	bool operator<(const node &p)const{
		if(x==p.x){
			return id<p.id;
		}else	return x<p.x;
	}
};
const int MAX_N=300005;
int n,Q;
node a[MAX_N];

int main()
{
	ios::sync_with_stdio(false);
	while(cin>>n){
		for(int i=0;i<n;++i)
		{
			cin>>a[i].x;
			a[i].id=i+1;
		}
		sort(a,a+n);
		cin>>Q;
		int l,r,x;
		for(int i=0;i<Q;++i)
		{
			cin>>l>>r>>x;
			int L=lower_bound(a,a+n,node{x,l})-a;
			int R=upper_bound(a,a+n,node{x,r})-a;
			cout<<R-L<<endl;
		}
	}
	return 0;
}

也可以用 pair<int,int>来排序

Code H :

#include<iostream>
#include<algorithm>
using namespace std;
 
const int MAX_N=300005;
int n,Q;
pair<int,int> data[MAX_N];
 
int main()
{
    ios::sync_with_stdio(false);
    while(cin>>n){
	    for(int i=0;i<n;i++)
	    {
	        cin>>data[i].first;
	        data[i].second=i+1;
	    }
	    sort(data,data+n);
	    cin>>Q;
	    int l,r,x;
	    for(int i=0;i<Q;++i)
	    {
	        cin>>l>>r>>x;
	        pair<int, int>* ll=lower_bound(data,data+n,pair<int,int>(x,l));
	        pair<int, int>* rr=upper_bound(data,data+n,pair<int,int>(x,r));
	        cout<<rr-ll<<endl;
	    }
	}
    return 0;
}


I-背包问题

思路:DFS+二分  比赛后突然灵光一现才ac掉,对于dp的话时间复杂度为 n*m=10^10肯定超时,而利用搜索,每个物体取和不取,复杂度也有 2^30=10^9也会超时(但是我看ac掉的代码竟然有这种思路过的,还只要2ms。。。这数据TM坑爹啊 (╯°Д°)╯︵ ┻━┻ )

由于直接搜索会超时,因此可以分别把前一半和后一半的所有情况搜索出来保存在数组 d1[],d2[]中,在将d2[]由小到大排序,在遍历d1[],每次只要 找到用二分查找到p=m-d1[i]+1在d2[]中的下标位置k,则ans+=k;这样最终ans就是所有的放法。这样的时间复杂度为 O(2^(n/2)*log(2^(n/2))=10^5

Code I:

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long LL;

const int MAX_N=100005;
int n,S,ans;
int n1,n2;
LL a[MAX_N];
LL d1[MAX_N],d2[MAX_N];

void DFS(int k,int m,LL sum);
int main()
{
	ios::sync_with_stdio(false);
	while(cin>>n>>S){
		ans=n1=n2=0;
		memset(d1,0,sizeof(d1));
		memset(d2,0,sizeof(d2));
		for(int i=0;i<n;++i)
			cin>>a[i];
		DFS(0,n/2,0);
		n1=n2;	n2=0;
		for(int i=0;i<n1;++i)
			d1[i]=d2[i];
		DFS(n/2,n,0);
		sort(d2,d2+n2);
		for(int i=0;i<n1;++i)
		{
			int p=S-d1[i];
			int k=lower_bound(d2,d2+n2,p+1)-d2;
			ans+=k;
		}
		cout<<ans<<endl;
	}
	
	return 0;
}

void DFS(int k,int m,LL sum)
{
	if(k==m){
		if(sum<=S)	d2[n2++]=sum;
		return;
	}
	DFS(k+1,m,sum);
	DFS(k+1,m,sum+a[k]);
}


J-are you ok  雷总的are you ok 。。。

思路 :线段树+二分查找  利用线段树维护区间的最大值,再用二分查找每次的询问值x,并修改其前一位值即可

Code J:

#include<iostream>
#include<stdio.h>
using namespace std;

const int MAX_N=1000006;
int n,Q;
int a[MAX_N];
int tree[MAX_N<<2];

void PushUp(int t);
void Build(int l,int r,int t);
void Update(int id,int x,int L,int R,int t);
int Query(int l,int r,int L,int R,int t);
int Lower_bound(int l,int r,int x);
int main()
{
//	ios::sync_with_stdio(false);
	while(~scanf("%d%d",&n,&Q)){
	//	memset(tree,0,sizeof(tree));
		for(int i=1;i<=n;++i)
			scanf("%d",&a[i]);
			//cin>>a[i];
		Build(1,n,1);
		for(int i=0,x;i<Q;++i)
		{
			scanf("%d",&x);
		//	cin>>x;
			int k=Lower_bound(1,n,x);
//			cout<<"##  ";
			if(k!=n){
				printf("%d\n",k);
				//cout<<k<<endl;
				if(k>=1){
					a[k]++;
					Update(k,a[k],1,n,1);
				}
			}else//	cout<<"are you ok"<<endl;
				printf("are you ok\n");
		}
	}
	
	return 0;
}

void PushUp(int t)
{
	tree[t]=max(tree[t<<1],tree[t<<1|1]);
}

void Build(int l,int r,int t)
{
	if(l==r){
		tree[t]=a[r];
		return;
	}
	int h=(l+r)>>1;
	Build(l,h,t<<1);
	Build(h+1,r,t<<1|1);
	PushUp(t);
}

void Update(int id,int x,int l,int r,int t)
{
	if(l==r){
		tree[t]=x;
		return;
	}
	int h=(l+r)>>1;
	if(h>=id){
		Update(id,x,l,h,t<<1);
	}else	Update(id,x,h+1,r,t<<1|1);
	PushUp(t);
}

int Query(int l,int r,int L,int R,int t)
{
	if(L>=l&&R<=r){
		return tree[t];
	}
	int h=(L+R)>>1,s1=0,s2=0;
	if(h>=l)	s1=Query(l,r,L,h,t<<1);
	if(h+1<=r)	s2=Query(l,r,h+1,R,t<<1|1);
	return max(s1,s2);
}

int Lower_bound(int l,int r,int x)
{
	while(l<=r){
		int h=(l+r)>>1;
		if(Query(1,h,1,n,1)>=x)	r=h-1;
		else	l=h+1;
	}
	return l-1;
}


K-序列求和

思路 :对于前 n2和 S=n*(n+1)*(2*n+1)/6,而 S要对 MOD=1000000007取模;由于S中要除以6,因此可以用乘法逆元求出6对于MOD的逆元 P=166666668; 那么 ans=(S%MOD*(P%MOD))%MOD即可,另一种思路是 用n*(n+1)*(2*n+1)提前消除6,n或(n+1)可以消除2,而n (n+1) (2*n+1)三种间必然有一个可以消除3,这样就可以直接取模了。

Code K:

#include<iostream>
using namespace std;
typedef long long LL;

const LL MOD=1000000007;
const LL P=166666668;	//6对于MOD的逆元 
LL n;

int main()
{
	ios::sync_with_stdio(false);
	while(cin>>n){
		LL a=n,b=n+1,c=2*n+1;
	//	LL ans=(((a%MOD*(b%MOD))%MOD*(c%MOD))%MOD*(P%MOD))%MOD;	//利用乘法逆元 
		if(a%2==0)	a/=2;
		else	b/=2;
		if(a%3==0)	a/=3;
		else	if(b%3==0)	b/=3;
		else	c/=3;
		LL ans=((a%MOD*(b%MOD))%MOD*(c%MOD))%MOD;
		cout<<ans<<endl;
	}
	
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值