Codeforces Round #643 (Div. 2) Solution

前言

rk44.如果T1 5min看出来能上榜1.
终于上紫了…

A A

真.暴力出奇迹.

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 ( 900 lg n   T ) O(900\lg n~T) .

赛时能想到这个AC方法是因为看到有人3min秒了,于是感觉是非常单纯的模拟(?).

B B

一个块的大小必须 \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;
}

C C

要满足 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 , t t=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;
}

D D

CF和AT最喜欢出构造题了.

这里有多种解法:

方法1

m y   i d e a my~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;
}

正确性证明:
k 0 , k [ 1 , S ] k明显\ne 0,即k\in[1,S] .
a = 1 a=1 时,序列有 1 , 2 1,2 ,对于任意 k [ 1 , S ] , 2 1 k k\in[1,S],我们都可以选取一些2和一些1构成k .
否则, k = [ 1 , a ) k=[1,a)都合法

方法2

基于前面的判断无解后, { 1 , 1... , s ( n 1 ) } , k = s / 2 \{1,1...,s-(n-1)\},k=s/2
证明:
在这里插入图片描述

方法3

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

E E

显然是个凸函数(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 ( ( log 1.5 1 0 9 ) n ) O((\log_{1.5} 10^9 )n)

F F

orz,rk2大神

我们充分利用22次的机会.
每次把一堆质数的幂的乘积输出,如果gcd得到了对应的质数,那么我们就考虑增大质数的幂.

2的幂无法正确求出,但是实际上22>30/2,所以误差正常.
其余的<850的质数我们都可以认为可以求得正确的指数.
最后我们*2输出即可.

然后,我们考虑忽略掉的<850的质数的情况:

  • 1 1 ,合法.
  • 质数,*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;
}


猜你喜欢

转载自blog.csdn.net/qq_42886072/article/details/106167498