Codeforces Round #520 (Div. 2)部分题解

h

题意:给定一个递增的序列,问一次最多可以拿掉多少个数后,还可以恢复原序列。比如  1 3 4 5 6 9 ,那么我拿掉 4 和 5 之后 ,还是可以通过 3 到 6 确定4 和 5的 ,所以答案是 2 。而  998 999 100 ,因为最大时1000,所以我可以把  999 和 1000 拿掉 这样通过 998 还是可以复原原序列。

题解:

1.先遍历一遍原数组找最长的序列,然后再分别从开头和结尾特殊处理一下

#include<bits/stdc++.h>
using namespace std;
int a[105];
int main()
{
	int n;cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	int t=0,ans=0;
	for(int i=2;i<=n;i++){
		if(a[i]==a[i-1]+1) t++,ans = max(ans,t);
		else t=0;
	}//得到的ans会是最长连续序列-1 
	t=0; 
	//开头处理 
	for(int i=1;i<=n;i++) {
		if(a[i]==i) t++;
		else break;
	}
	
	//末尾处理 
	int cur=1000,tt=0;
	for(int i=n;i>=1;i--) {
		if(a[i]==cur) tt++,cur--;
		else break;
	}
	
	if(tt>=2||t>=2)//一定要个数大于2才能确定是连续的 
	cur = max(tt,t);
	else cur=1;
	
	ans = max(ans-1,cur-1);
	printf("%d\n",ans);
 }

2.其实可以把a[0]值为0,把a[n+1]值为1001,这样我们就只要找到最长的连续序列,然后减2就是答案了。

#include<bits/stdc++.h>
using namespace std;
int a[105];
int main()
{
	int n;cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	a[0]=0;a[n+1]=1001; 
	int t=0,ans=0;
	for(int i=1;i<=n+1;i++){
		if(a[i]==a[i-1]+1) t++,ans = max(ans,t);
		else t=0;
	}
	if(ans>=1)//如果存在连续的序列 
	printf("%d\n",ans-1);
	else puts("0");
 }

题意:给定一个数,你可以对它进行如下两个操作:  1.乘以任意正整数倍数    2.求平方根    问你怎么操作能得到最小的数,并使操作次数最少。

 

题解:

           首先可以肯定的是一个数可以分解质因数为  n = q1^a1 * q2^a2 * q3^a3.....; 显而易见的我们能求得的最小的这个数肯定是

q1*q2*q3...; 那么当我们进行平方根的时候,就是对这些质数q1^a1 * q2^a2 * q3^a3.....进行平方根。首先要判断这些质数的幂

是否相等且都为2的次方, 如果不是,为了能使操作数最少,第一步就要乘以一个数将这些幂都变成2的次方且都相等,然后再

不断求平方根就行了。

           具体做法:分解质因数,记录每个质因数的个数,最大的那个数标记为ma,能得到的最小的数就是每个质数相乘,操作

数就是ma对应的2的幂次方,如果ma不够或者其它数不够,操作数就需要加1。(也就是需要乘以一个数将他们都变成2的幂次)   

          例如5184 = 2^6 * 3^4;  能得到的最小的数是2*3=6;最小操作数就是 :我们要先乘以一个数将 2^6 * 3^4变成 2^8 * 3^8,然后再进行三次平方根,所以最小操作数是4。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6+10; 
int a[maxn]; 
int main()
{
	int n;
	cin>>n;
	int sum =1,t=n,i,ma=1,ans=0;
	for(int i=2;i<=t;i++){
		if(t%i==0) sum*=i;//寻找最小的数 
		while(t%i==0){//分解质因数 
			t/=i;
			a[i]++;//记录每个质数的个数 
			ma=max(ma,a[i]);//找到最大个数 
		}
	}
	int cur=0;//保存要进行的平方根的操作数 
	
	for(int i=0;i<=20;i++){
		int t = pow(2,i);//t就是2的幂次方 
		if(ma==t) {//如果最大数等于t,说明最大数够了 
			cur=i;
			break;
		}
		if(ma<t){//如果最大数小于t,说明最大数还不够,所以ans要值为1 
			cur=i;
			ma = t;//并将最大数更新为t 
			ans=1;
			break;
		}
	}
	//此时最大数够了,但是我们还要判断其它数够不够 
	for(int i=1;i<=n;i++)
	if(a[i]&&a[i]!=ma){ //如果不够也要将ans值为1 
			ans=1;
			break;
	}
	
	cout<<sum<<' '<<ans+cur<<endl;
}

 

c题应该要比b题简单一些,我希望你能不看题解做出来。

题意:

            给你一个只包含0和1的串,你每次可以从中拿一个数,拿走之后串中其他位置的数就会相应加上其值。比如1011,我先

把第一个1拿走,这个时候ans+=1, 串就变成了122,我再把最后一个2拿走,ans+=2,串就变成了34,再把4拿走,ans+=4,串就

变成了7,最后把7拿走,ans+=7。最后ans= 14.   有q次询问,每次询问你这个串的一个区间,问以怎么样的顺序拿可以使ans最大。

 

题解:前缀和+快速幂。

先前缀和处理一下,算出给定区间1的个数,以及0的个数。肯定贪心先取1,再取0,最后会发现实际上是在求两个等比 数列的

前n项和。求前n项和用到了快速幂。

 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
const int maxn = 1e5+10;
char s[maxn];
int sum[maxn];
ll powmod(ll a,ll b) {ll res=1;a%=mod;for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
int main()
{
	int n,m;
	cin>>n>>m;
	cin>>s+1;
	for(int i=1;i<=n;i++)
		sum[i]=sum[i-1]+(s[i]-'0');//前缀和 
	while(m--){
		int l,r;ll ans=0;
		scanf("%d%d",&l,&r);
		ll a = sum[r]-sum[l-1];//1的个数 
		ll b = r-l+1-a;//0的个数 
		ans = (powmod(2,a)-1)%mod;//先取1 
		ans = ans + ans*(powmod(2,b)-1)%mod;//再取0 
		cout<<ans%mod<<endl;
	}
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值