牛客练习赛23(题解)

                                                                                    先扔一波题目

A托米的赌球

这一题的大意就是托米有一些面值不同的硬币,想用尽量少的硬币凑出给出的值。

这题刚看到的时候还以为是DP,或者是数论(前几天做这类题做疯了),但一看数据范围……果断排除。

重新看了一下托米有的硬币的面值,这不就是贪心吗,每次能用面值大的就用面值大的,然后就很开心地去写代码了。

#include<bits/stdc++.h>
#define mem(x) memset(x,0,sizeof(x));
using namespace std;
int p[15]={10000,5000,2000,1000,500,200,100,50,20,10,5,2,1};//直接用分
long long ans[15],t,n,m;//注意范围 10^9 * 100 > 2^31-1
int main(){
	cin>>t;
	while(t--){
		mem(ans);
		cin>>n>>m;
		n=n*100+m;    //把它转成分的形式
		for(int i=0;i<13;i++){
			ans[i]=n/p[i];
			n%=p[i];
		}
		for(int i=0;i<13;i++) printf("%lld ",ans[i]); if(t)printf("\n");//注意格式(罚时20m)
	}
	return 0;
}

 

 

B托米的划分

 

这题刚看到的时候是有些懵逼的,于是打表找规律     于是我就想,对于每个数肯定有一种固定的分法,于是凭借我强大的猜测力(乱搞能力)推测(乱捅)出了分法。

就是比如说当前的数字是n,就把它分成 (1,n-1)然后n-1再继续分下去,我们可以发现就是求1~n-1的和,就是n*(n-1)/2。

代码嘛,100b了:

#include<bits/stdc++.h>
using namespace std;
long long t,n;//注意变量类型
int main(){
	cin>>t;
	while(t--){
		cin>>n;
		cout<<(n)*(n-1)/2<<endl;
	}
	return 0;
}

 

C托米的位运算

第三题嘛……

其实一开始是没看懂题目,原来是很简单的,就是给出一些数,要从中取出一些数,使他们所有数按位与的结果的lowbit值最大的情况下还要然选出来的数尽量多。

这题一开始想了两个贪心,结果一个28.几%,令一个71.几%,加起来刚好100%……

后面有换了种思想,就是我没可以枚举这个lowbit值,然后把这一位是一的全部选出来,看最后按位与的结果是否lowbit值刚好为我枚举的,看了我的代码就懂了(还是挺短的)

#include<bits/stdc++.h>
#define lowbit(x) x & -x  //lowbit在这!!
using namespace std;
const int N = 100005;
int sz,n,a[N],ans[N];
int main(){
	int p=0;
	scanf("%d", &n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);//日常输入
	for(int i=30;i>=0;i--){ //枚举看是哪一位为一(lowbit值)
		int s=2147483647;  // 2^31 -1 ->(1111……1)2
		sz=0;
		p=(1<<i);
		for(int j=1;j<=n;j++){
			int t=(a[j] & p);  //如果当前位是1,才能取出,不然那位与后就会变成零
			if(t) s=(int)(s&a[j]),sz++,ans[sz]=a[j];//利用与的性质,能与就尽量与。
		}
		s=lowbit(s);  
		if(s==(1<<i)) break; //check 一下 
	} 
	printf("%d\n",sz);
	for(int i=1;i<=sz;i++){
		printf("%d",ans[i]);
		if(i!=sz) printf(" ");//注意格式+1
	}
	return 0;
}

 

D托米的咒语

这题的题意也比较好理解吧,就是看a……i的排列有几个出现在了字符串s里面。

这题正常人的思路就是枚举全排列,然后带进去试,我一开始也是这么想的,但算了一下最坏时间复杂度9!*3000≈10^9

会超时(但赛后听说它们就是这样卡过了!!),我的方法也十分简单明了,就是在枚举全排列的基础上,在匹配的

的时候做了一些优化,首先,对于我们当前要匹配的一个字母,如有多个满足条件的我们是不是会贪心地取最前面一个满足要求的,这里我们可以用二分查找来优化,所以总的时间复杂度就是O(log2(|s|))的,只不过常数是9!*9,有点大,不过比起前面那个还是好了很多。

看了代码就懂了:

#include<bits/stdc++.h>
using namespace std;
const int N = 3005;
int zm[11][N],sz[11],d[11],p[11],ans;
string st;
bool check(){
	int pos=0;//pos 为当前匹配到 s 的第几位
	for(int i=1;i<=9;i++){//把排列带进去check一下
		int pj=pos;//临时变量
		pos=lower_bound(zm[p[i]]+1,zm[p[i]]+1+sz[p[i]],pj) - zm[p[i]];
		if(zm[p[i]][pos]<=pj) pos++;  //判断是否在上一个位置之后
		pos=zm[p[i]][pos]; 
		if((st[pos]-'a')!=p[i]) return 0; //是否有这个字母可以满足要求
	}
	return 1;
}
void dfs(int x){//枚举全排列
	if(x>=9){
		ans+=check();
		return;
	}
	for(int i=0;i<9;i++){
		if(!d[i]){
			d[i]=1;
			p[x+1]=i;
			dfs(x+1);
			d[i]=0;
		}
	}
}
int main(){
	cin>>st;
	int n=st.length();
	st=" "+st;  //方便处理……
	for(int i=1;i<=n;i++){
		if(st[i]<='i') zm[st[i]-'a'][++sz[st[i]-'a']]=i;//把每个位置按字母分类
	}
	dfs(0);
	printf("%d",ans);//开心地输出答案
	return 0;
}

 

待填坑……(其实是题解还没出)

题解链接->官方的:https://uploadfiles.nowcoder.com/files/20180728/8030387_1532751445741_%E7%89%9B%E5%AE%A2%E7%BB%83%E4%B9%A0%E8%B5%9B23%E9%A2%98%E8%A7%A3.pdf

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值