题解 Smooth

传送门

咕了蚯蚓这题+前一天被蚊子折腾了半宿没睡=全场几乎就我这题分最低……

发现这里光滑数是不断乘出来的……记得这是一个很经典的套路,然而当时我咕了

  • 求一个每个值都是 \(\{p_i\}\) 中至少一个数的倍数的数列第 \(k\) 项:
    举个例子,求2的所有倍数及3的所有倍数的并集中的第 \(k\)
    一大难点在于排序和去重
    然而实际上可以用队列处理,可以免去排序去重的过程
    具体来说,对每个因子维护一个队列,初始只有这个因子本身
    每次从所有队列的首元素中取出最小的那个,这个元素即为数列第 \(i\)
    在所有大于等于该元素的因子的队列后加入该元素与这个因子的乘积
    容易发现,这样保证了所有可能性都一定出现过,且无重
    我们把一个可能性表示为 \(\prod p_i\) ,则 \(i\) 一定单调不降
    则每个可能性都可以唯一表示,所以无重
    假设一个 \(x\) 被漏掉了,那么 \(\frac{x}{p_{max\{i\}}}\) 也一定被漏掉了,类推得队列中初始为空
    由于所选元素单增,每个队列对应因子不变,所以队列中元素大小也单增

于是就是板子了

Code:

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 10000010
#define ll long long 
//#define int long long 

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline ll read() {
	ll ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int b, k;

namespace table{
	bool vis[N];
	int pri[N], cnt;
	void init() {
		for (int i=2; i<=100; ++i) {
			if (!vis[i]) pri[++cnt]=i;
			for (int j=2; j<=100&&i*j<=1000; ++j) 
				vis[i*j]=1;
		}
		for (int i=1; i<=cnt; ++i) cout<<pri[i]<<' '; cout<<endl;
	}
	void solve() {
		init();
	}
}

namespace force{
	int pri[N], pcnt;
	bool npri[N], vis[N];
	void solve() {
		npri[0]=npri[1]=1;
		int lim=1e7;
		for (int i=2; i<=lim; ++i) {
			if (!npri[i]) pri[++pcnt]=i;
			for (int j=1; j<=pcnt&&i*pri[j]<=lim; ++j) {
				npri[i*pri[j]]=1;
				if (!(i%pri[j])) break;
			}
		}
		for (int i=b+1; i<=pcnt; ++i) 
			for (int j=1; pri[i]*j<=lim; ++j) 
				vis[pri[i]*j]=1;
		int cnt=0;
		for (int i=1; i<=lim; ++i) {
			if (!vis[i]) {
				//cout<<i<<' ';
				if (++cnt==k) {
					//cout<<endl;
					printf("%d\n", i);
					exit(0);
				}
			}
		}
	}
}

namespace task1{
	ll qpow(ll a, ll b) {
		ll ans=1; 
		while (b) {
			if (b&1) ans=(ans*a);
			a=a*a; b>>=1;
		}
		return ans;
	}
	void solve() {
		if (k==1) puts("1");
		else printf("%lld\n", qpow(2, k-1));
		exit(0);
	}
}

namespace task2{
	ll sta[N], top;
	void solve() {
		ll a=1, b;
		for (int i=1; i<int(1e6); ++i) {
			if (a*3ll<0) break;
			//cout<<"upd2: "<<a<<endl;
			b=1;
			for (int j=1; b>0&&a*b>0&&a*b<(ll)(1e18)&&b<int(1e6); ++j) {
				//cout<<"upd3: "<<a<<' '<<b<<endl;
				sta[++top]=a*b;
				b*=3ll;
			}
			a*=2ll; if (a<0) break;
		}
		sort(sta+1, sta+top+1);
		//for (int i=1; i<=top; ++i) cout<<sta[i]<<' '; cout<<endl;
		printf("%lld\n", sta[k]);
		exit(0);
	}
}

namespace task{
	queue<ll> q[20];
	ll pri[]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71};
	void solve() {
		for (int i=1; i<=b; ++i) q[i].push(pri[i]);
		ll minn;
		for (int i=1,mini; i<=k-1; ++i) {
			minn=(ll)(1e18);
			for (int j=1; j<=b; ++j)
				if (q[j].front()<minn) 
					minn=q[j].front(), mini=j;
			q[mini].pop();
			for (int j=mini; j<=b; ++j) 
				q[j].push(minn*pri[j]);
		}
		printf("%lld\n", minn);
		exit(0);
	}
}

signed main()
{
	b=read(); k=read();
	//if (b==1) task1::solve();
	//else if (b==2) task2::solve();
	//else force::solve();
	task::solve();
	
	return 0;
}
posted @ 2021-08-07 20:42  Administrator-09  阅读(11)  评论(0编辑  收藏  举报