1. 程式人生 > >【codeforces】Round #520 (Div. 2) A+B+C+D

【codeforces】Round #520 (Div. 2) A+B+C+D

目錄

A - A Prank

B - Math

C - Banh-mi

D - Fun with Integers


【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

【題意】給你一個數字,有兩種操作:

  1. 乘x(x為任意正整數)
  2. 開方

每次只能執行一種操作,求可以獲得的最小數和操作的次數。

【分析】自己列幾個例子,就可以發現可以得到的最小的數字是該數所有的質因數的乘積(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;
}