牛客小bai月赛40——A、I、G、E、F

A、数字游戏(思维,奇偶)

思路:

先判断 1 出现的次数 cnt 的奇偶,再判断其二进制第 0 位是否为 1.
如果是偶数,要变为奇数,操作次数+1.
如果第 0 位为 1,那么需要操作 2*cnt-1 次;否则操作 2*cnt+1 次。

加快读快输 (网上抄的板子)

Code:

inline int read()
{
    
    
	int x=0;	//输出结果; 
	char c=getchar();	//先读个字符; 
	while(c<'0'||c>'9') c=getchar();	//读入非数字字符; 
	while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();	//读入数字; 
	return x;
}

void print(int x)
{
    
    
	char P[10005];int w=0;
	if(x<0) putchar('-'),x=-x;//特判负数 
	if(x==0) putchar('0');
	while(x) P[++w]=x%10+'0',x/=10;//分离各位 
	for(int i=w; i>=1; i--) putchar(P[i]);//逆序输出 
	puts("");
}

void check(int n)
{
    
    
	string s;
	int sum=0;
	while(n)
	{
    
    
		if(n&1) s+='1',sum++;
		else s+='0';
		n >>= 1;
	}
	cnt=0;
	if(sum%2==0)
	{
    
    
		cnt++;
		sum--;
	}
	if(s[0]=='1') cnt+=sum*2-1;
	else cnt+=sum*2+1;
	
	print(cnt);
}

int main(){
    
    
	cin>>T;
	while(T--)
	{
    
    
		n=read();
		check(n);
	}
	
	return 0;
}

I、体操队形(全排列)

思路:

因为n最多到10,所以直接求全排列。
两种方式:
1.dfs,遍历每一位看放什么数,每遍历一层判断当前排列是否满足,不满足及时return。
2.nextmutation函数:暴力判断即可。

Code:

const int N = 200010, mod = 1e9 + 7;
int T, n, m, a[N];
int pre[N],ans;
int f[N];

void dfs(int u)
{
    
    
	for(int i=1;i<=n;i++){
    
    
		if(a[pre[i]]==0) continue;
		if(a[pre[i]]<a[i]) return;
	}
	
	if(u==n+1){
    
    
		ans++;return;
	}
	
	for(int i=1;i<=n;i++)
	{
    
    
		if(f[i]) continue;
		
		a[u]=i;
		f[i]=1;
		dfs(u+1);
		f[i]=0;
		a[u]=0;
	}
}

int main(){
    
    
	cin>>n;
	for(int i=1;i<=n;i++) cin>>pre[i];
	dfs(1);
	
	cout<<ans;
	
	return 0;
}

nextmutation函数板子:

int main(){
    
    
	cin>>n;
	for(int i=1;i<=n;i++) a[i]=i;
	
	do
	{
    
    
		for(int i=1;i<=n;i++) cout<<a[i]<<" ";
		cout<<endl;
		
	}while(next_permutation(a+1,a+n+1));
	
	return 0;
}

G、空调遥控(差分前缀和)

思路:

每个人的范围为(ai-k,ai+k),最终选一个数,满足的人最多。
将每个人的所在的范围中的所有数+1——差分标记,最终前缀和还原。
判断哪个数最大便是满足的最多人数。

Code:

const int N = 2000010, mod = 1e9 + 7;
int T, n, m, a[N];

int main(){
    
    
	cin>>n>>m;
	for(int i=1;i<=n;i++){
    
    
		int x;cin>>x;
		x+=1000000;
		a[x-m]++,a[x+m+1]--;
	}
	
	int ans=0;
	for(int i=0;i<=2000000;i++){
    
    
		a[i]+=a[i-1];
		ans=max(ans,a[i]);	
	}
	cout<<ans;
	
	return 0;
}

E、分组(二分答案)

思路:

最大值最小,二分答案。

check:
如果当前值和前一值不同或者人数达到mid,就新开一组。
如果最终的组数不超过m,则满足,继续往前分。
(既然分不超过m组就满足每组的最多人数不超过mid,那么分m组肯定更满足。)

Code:

const int N = 200010, mod = 1e9 + 7;
int T, n, m, a[N];

bool check(int mid)
{
    
    
	int cnt=0,ans=0;
	for(int i=1;i<=n;i++)
	{
    
    
		if(a[i]!=a[i-1]||cnt==mid) ans++,cnt=1;
		else cnt++;
	}
	if(ans<=m) return 1;
	return 0;
}

int main(){
    
    
	cin>>n>>m;
	int cnt=0;
	for(int i=1;i<=n;i++){
    
    
		cin>>a[i];
		if(!mp[a[i]]) cnt++,mp[a[i]]=1;
	}
	if(cnt>m){
    
    
		cout<<-1;return 0;
	}
	
	sort(a+1,a+n+1);
	
	int l=1,r=n;
	while(l<r)
	{
    
    
		int mid=l+r>>1;
		if(check(mid)) r=mid;
		else l=mid+1;
	}
	cout<<l;
	
	return 0;
}

这里 有二分答案的详解和典例。


F、过桥(bfs,最短路)

思路:

两种方法:
1.bfs计算最少操作次数,第一次到达的便是最少的。
2.建边跑最短路。

Code:

1.bfs:

void bfs()
{
    
    
	queue<int> que;
	que.push(1);
	mp[1]=0;
	
	while(que.size())
	{
    
    
		int x=que.front();que.pop();
		if(x>0){
    
    
			for(int i=x+1;i<=min(n,x+a[x]);i++)
			{
    
    
				if(!mp.count(i)) que.push(i),mp[i]=mp[x]+1;
			}
		}
		else{
    
    
			for(int i=1;i<=max(1,x+a[x]);i++){
    
    
				if(!mp.count(i)) que.push(i),mp[i]=mp[x]+1;
			}
		}
	}
}
int main(){
    
    
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	
	bfs();
	
	if(mp[n]) cout<<mp[n];
	else cout<<-1;
	
	return 0;
}

2.dijstra最短路:

const int N = 2010, mod = 1e9 + 7;
int T, n, m, a[N];
int f[N];
int e[N*N],ne[N*N],h[N],idx;
int dist[N];

void add(int x,int y){
    
    
	e[idx]=y,ne[idx]=h[x],h[x]=idx++;
}

void dij()
{
    
    
	mem(dist,0x3f);
	dist[1]=0;
	priority_queue<PII,vector<PII>,greater<PII> > que;
	que.push({
    
    0,1});
	
	while(que.size())
	{
    
    
		int x=que.top().se;que.pop();
		if(f[x]) continue;
		f[x]=1;
		
		for(int i=h[x];i!=-1;i=ne[i])
		{
    
    
			int tx=e[i];
			if(dist[tx]>dist[x]+1){
    
    
				dist[tx]=dist[x]+1;
				que.push({
    
    dist[tx],tx});
			}
		}
	}
}

int main(){
    
    
	cin>>n;
	
	mem(h,-1);
	
	for(int i=1;i<=n;i++)
	{
    
    
		int x;cin>>x;
		if(x>0){
    
    
			for(int j=i+1;j<=i+x;j++) add(i,j);
		}
		else{
    
    
			for(int j=1;j<=max(1,i+x);j++) add(i,j);
		}
	}
	
	dij();
	
	if(dist[n]!=0x3f3f3f3f) cout<<dist[n];
	else cout<<-1;
	
	return 0;
}

待更。。

猜你喜欢

转载自blog.csdn.net/Mr_dimple/article/details/121172893