【codeforces】Round #520 (Div. 2) A+B+C+D
目錄
【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;
}