目录
【A - A Prank】
题目链接:http://codeforces.com/contest/1062/problem/A
【题意】
给你一串序列,长度为n,在1-1000范围内严格递增。
问最多在序列中删掉多少元素可以使填数的方式唯一(仍然为严格递增序列)
如12345,就可以删掉中间的234变成1_ _ _5,要求填进去的数仍然满足严格递增,就只能填2 3 4。
【分析】
遍历一遍数组,因为范围是1-1000,那么使得a[0]=0,a[n+1]=1001,最后求得的长度len-2即是所需要的长度。加上这两个元素是为了考虑如果开始和最后都可以删除的情况。
【代码】
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e2+5;
int a[maxn];
int main()
{
int n;scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
a[0]=0;a[n+1]=1001;
int len=1,pre=0,ans=0;
for(int i=1;i<=n+1;i++)
{
if(pre+1==a[i])
len++,pre++;
else
{
ans=max(len-2,ans);
len=1;
pre=a[i];
}
}
ans=max(ans,len-2);
printf("%d\n",ans);
return 0;
}
【B - Math】
题目链接:http://codeforces.com/contest/1062/problem/B
【题意】给你一个数字,有两种操作:
- 乘x(x为任意正整数)
- 开方
每次只能执行一种操作,求可以获得的最小数和操作的次数。
【分析】自己列几个例子,就可以发现可以得到的最小的数字是该数所有的质因数的乘积(divide函数分解质因数),最小的操作次数就是求每个质因数的幂数,然后将其化成最小的2的幂次。举几个例子就可以看出来了。即所有的质因数的指数部分都是偶数,然后通过乘以X来使其达到所有质因数的指数都是2的次幂,最后不断开平方,得到我们想要的答案。
【代码】
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5;
int p[maxn],c[maxn];//p[i]存质因数,c[i]存指数
int len;
int divide(int n)//质因数分解
{
int cnt=0;
for(int i=2;i*i<=n;i++)
{
if(n%i==0)
{
p[++cnt]=i;
c[cnt]=0;
while(n%i==0)
{
n/=i;
c[cnt]++;
}
}
}
if(n>1)
p[++cnt]=n,c[cnt]=1;
len=cnt;
int pp=1;
for(int i=1;i<=cnt;i++) pp*=p[i];
return pp;//返回质因数之积
}
int main()
{
len=0;
int q=1;
int aa[32]={0};//存2的i次幂对应的数
aa[0]=1;
for(int i=1;i<32;i++)
q*=2,aa[i]=q;
memset(p,0,sizeof(p));
memset(c,0,sizeof(c));
int n;scanf("%d",&n);
int ans1=divide(n);
int ans2=0;
sort(c+1,c+1+len);
int mm=c[len],index=0;
for(int i=1;i<32;i++)
{
if(aa[i]>=mm)
{
index=i;break;
}
}
ans2=index;
if(mm!=c[1])index++;
if(aa[index]!=mm)ans2++;
if(ans1==n)ans2=0;
cout<<ans1<<" "<<ans2<<endl;
return 0;
}
【C - Banh-mi】
题目链接:http://codeforces.com/contest/1062/problem/C
【题意】给你一个01串,q次询问给出区间[l,r],每次拿掉一个数字获得相对应数字的分数,并使其他位增加相对应的分数。求最高可以获得的分数。
【分析】对于每个区间贪心,先拿1,再拿0;设该区间1的个数为x,自己列几个例子就可以发现,
依次取1的时候等比数列:1,2,4,...,2^x-1
依次取0的时候等比数列:2^x-1,2(2^x-1),4(2^x-1),...
做数学运算,各求其前n项和,相加,得最后结果是:(2^x-1)2^(len-x);
所以,要用到快速幂
并且,每次都是要用到区间里1的个数,如果每次都求一遍的话会超时,所以,预处理一下1的个数,前缀和
【代码】
#include<cstring>
#include<iostream>
#include<string>
#include<cstdio>
#include<algorithm>
using namespace std;
#define ll long long
const ll mod=1e9+7;
const ll maxn=1e5+5;
char s[maxn];
int num[maxn];//记录该位之前1的个数
ll qpow(ll a,ll b)
{
ll ans=1;
while(b)
{
if(b&1)ans=ans*a%mod;
a=a*a%mod;
b/=2;
}
return ans%mod;
}
int main()
{
int n,q;
scanf("%d%d",&n,&q);
scanf("%s",s+1);
num[0]=0;
for(int i=1;i<=n;i++)
num[i]+=num[i-1]+(s[i]=='1'?1:0);
int l,r;
while(q--)
{
int len=0,x1=0;
scanf("%d%d",&l,&r);
len=r-l+1;
x1=num[r]-num[l-1];
// cout<<"x1="<<x1<<endl;
ll ans=(qpow(2,x1)-1)%mod * (qpow(2,len-x1)%mod)%mod;
printf("%lld\n",ans);
}
return 0;
}
【D - Fun with Integers】
题目链接:http://codeforces.com/contest/1062/problem/D
【题意】输入一个正整数n,求[2,n]区间内绝对值成倍数关系整数对的和。
如,[2,5],有2,4;2,-4;-2,4;-2,-4四组,每组倍数的绝对值是2,所以最终答案是2×4=8;
【分析】枚举。但是枚举也要注意方法,不然还是会超时的。我一开始直接俩循环,外层套i,内层套与i成倍数的数从i*2~n但这样显然!会超时!!蠢死了 就直接内层是倍数并约束i*j<=n,这样会少了很多循环,然后这个倍数乘4就好了
【代码】
#include<cstring>
#include<iostream>
#include<string>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
int main()
{
ll n;scanf("%lld",&n);
ll n2=n/2,ans=0;
for(ll i=2;i<=n2;i++)
for(ll j=2;i*j<=n;j++)
ans+=j*4;
printf("%lld\n",ans);
return 0;
}