Codeforces Round #643 (Div. 2) Solution

前言

rk44.如果T1 5min看出來能上榜1.
終於上紫了…

AA

真.暴力出奇跡.

int T,a,b;
ll n,m,ans;

void calc(ll x) {
	while(x) {
		int y=x%10;
		a=min(a,y);
		b=max(b,y);
		x/=10;
	}
}

int main() {
	qr(T); while(T--) {
		qr(n); qr(m);
		while(--m) {
			a=9,b=0;
			calc(n);
			if(!a) break;
			n+=a*b;
		}
		pr2(n);
	}
	return 0;
}

不會TLE的原因:9*9=81,所以k極大時百位一定會出現0,複雜度至多O(900lgn T)O(900\lg n~T).

賽時能想到這個AC方法是因爲看到有人3min秒了,於是感覺是非常單純的模擬(?).

BB

一個塊的大小必須\ge塊內權值的最大值.
貪心起見,我們讓塊大小==權值最大值,這樣即可分出儘量多的塊.
同時,最優做法肯定是對排序後的權值不斷取前綴組成塊. 具體證明可以用微擾.

int T,n,a[N],ans,last;

int main() {
	qr(T); while(T--) {
		qr(n);for(int i=1;i<=n;i++) qr(a[i]);
		sort(a+1,a+n+1); ans=last=0;
		for(int i=1;i<=n;i++) 
			if(i-last>=a[i]) ans++,last=i;
		pr2(ans);
	}
	return 0;
}

CC

要滿足x+y>z,x[a,b],y[b,c],z[c,d]x+y>z,x\in[a,b],y\in[b,c],z\in [c,d].
我們考慮計算對於每個t=x+y,tt=x+y,t爲定值時的方案數.
然後我們求一下後綴和即可.

int a,b,c,d;
ll v[N],s,ans;

int main() {
	qr(a); qr(b); qr(c); qr(d);
	for(int i=b+c;i>=a+b;i--) {
		ll l=max(a,i-c),r=min(b,i-b);
		ll L=max(b,i-b),R=min(c,i-a);
		v[i]=min(r-l+1,R-L+1);
	}
	for(int i=b+c;i>=c;i--) {
		if(i<=d)ans+=s;
		s+=v[i];
	}
	pr2(ans);
	return 0;
}

DD

CF和AT最喜歡出構造題了.

這裏有多種解法:

方法1

my ideamy~idea
均值法

int n,m,a;

int main() {
	qr(n); qr(m); 
	if((a=m/n)==1) puts("NO");
	else {
		puts("YES");
		int b=m%n,i=1;
		for(i=1;i<=b;i++) pr1(a+1);
		for(   ;i<=n;i++) pr1(a);
		printf("\n%d\n",a-1);
	}
	return 0;
}

正確性證明:
k0,k[1,S]k明顯\ne 0,即k\in[1,S].
a=1a=1時,序列有1,21,2,對於任意k[1,S],21kk\in[1,S],我們都可以選取一些2和一些1構成k.
否則,k=[1,a)k=[1,a)都合法

方法2

基於前面的判斷無解後,{1,1...,s(n1)},k=s/2\{1,1...,s-(n-1)\},k=s/2
證明:
在這裏插入圖片描述

方法3

官方題解:{2,2,s2(n1)},k=1\{2,2,s-2*(n-1)\},k=1.

EE

顯然是個凸函數(OIer從來只猜結論,不證明)

int n,h[N],a,b,c;
ll ans=1e18;

ll calc(ll t) {
	ll x=0,y=0;
	for(int i=1;i<=n;i++)
		if(h[i]<=t) x+=t-h[i];
		else y+=h[i]-t;
	ll s=0,z,res=0;
	if(c<a+b) {
		z=min(x,y);
		s+=z*c;
		x-=z; y-=z;
	}
	s+=x*a+y*b;
	ans=min(ans,s);
	return s;
}

int main() {
	qr(n); qr(a); qr(b); qr(c);
	int l=1e9,r=0,lmid,rmid,len;
	for(int i=1;i<=n;i++) qr(h[i]),l=min(l,h[i]),r=max(r,h[i]);
	while(r-l>3) {
		len=r-l+1;
		lmid=l+len/3;
		rmid=r-len/3;
		if(calc(lmid)<calc(rmid)) r=rmid-1;
		else l=lmid+1;
	}
	while(l<=r) calc(l++);
	pr2(ans);
	return 0;
}

複雜度:O((log1.5109)n)O((\log_{1.5} 10^9 )n)

FF

orz,rk2大神

我們充分利用22次的機會.
每次把一堆質數的冪的乘積輸出,如果gcd得到了對應的質數,那麼我們就考慮增大質數的冪.

2的冪無法正確求出,但是實際上22>30/2,所以誤差正常.
其餘的<850的質數我們都可以認爲可以求得正確的指數.
最後我們*2輸出即可.

然後,我們考慮忽略掉的<850的質數的情況:

  • 11,合法.
  • 質數,*2正好吻合.
  • 質數*質數,實際最多 *4,誤差允許.
  • 質數* 質數*質數,顯然不能再加質因數了(*2就爆了),所以輸出2,實際爲8,答案合法.
#include<map>
#include<set>
#include<queue>
#include<cmath>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lc (x<<1)
#define rc (x<<1|1)
#define gc getchar()//(p1==p2&&(p2=(p1=buf)+fread(buf,1,size,stdin),p1==p2)?EOF:*p1++)
#define mk make_pair
#define pi pair<int,int>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=1e4+50,size=1<<20;

//char buf[size],*p1=buf,*p2=buf;
template<class o> void qr(o &x) {
	char c=gc; x=0; int f=1;
	while(!isdigit(c)){if(c=='-')f=-1; c=gc;}
	while(isdigit(c)) x=x*10+c-'0',c=gc;
	x*=f;
}
template<class o> void qw(o x) {
	if(x/10) qw(x/10);
	putchar(x%10+'0');
}
template<class o> void pr1(o x) {
	if(x<0)x=-x,putchar('-');
	qw(x); putchar(' ');
}
template<class o> void pr2(o x) {
	if(x<0)x=-x,putchar('-');
	qw(x); puts("");
}

bool v[N];
int prime[N],tot,T,ans,n;

struct node {
	int x,y,z;//冪,指數,質數
	bool operator <(node b) const {
		return y==b.y?x>b.x:y<b.y;
	}
}tmp,b[66];
priority_queue<node> q;

int main() {
	n=N-5;
	for(int i=2;i<=n;i++) if(!v[i]) {
		prime[++tot]=i;
		for(int j=i*i;j<=n;j+=i) v[j]=1;
	} 
	qr(T); while(T--) {
		while(!q.empty()) q.pop(); ans=1;
		for(int i=1;i<=tot;i++) q.push((node){prime[i],1,prime[i]});
		for(int j=1;j<=22;j++) {
			ll x=1; int cnt=0;
			while(!q.empty()) {
				b[++cnt]=q.top();
				if(1.0*x*b[cnt].x>=1e18) break;
				q.pop(); x*=b[cnt].x;
			}
			printf("? %lld\n",x);
			fflush(stdout);
			qr(x);
			for(int i=1;i<cnt;i++) 
				if(x%b[i].x==0) {
					ans/=b[i].y;
					b[i].y++;
					ans*=b[i].y;
					b[i].x*=b[i].z;
					q.push(b[i]);
				}
		}
		printf("! %d\n",ans*2);
	}
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章