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;
}
}