codeforces1469D. Ceil Divisions

https://codeforces.com/contest/1469/problem/D

这题观察发现一个比较优的策略

我们选择一个基数c,然后让n/(n/c), (n/c)/(n/c/c)....这样下去,把这些数字都变成c,然后最后再来一遍用c把他们变成1,最后用2把c变成1,那么最后就剩2这个2了,其他都是1

其他不在这中间考虑的数字我们就首先让他们全部/n变成1

所以对于3-n这些数字,只有c要让他不断/2,然后 n/c,n/c/c这些数字要先变c再变1,其他的数字都是1次变1,

所以这题本质上就是让log_c{n}+log_2{c}最小

数学基础扎实的人一下就会了,隔壁家20多岁还在打数理基础的叔叔研究了好久呜呜呜呜,可千万不要学我

最后试出来c=8在n=2e5下是可行的

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxl=3e5+10;

int n,m,k,cnt,tot,cas;
int a[maxl];
bool vis[maxl];
char s[maxl];
typedef pair<int,int> p;
vector<p> ans,ans2;

inline void prework()
{
	scanf("%d",&n);
//	n=2e5;
	for(int i=1;i<=n;i++)
		vis[i]=false;
	ans.clear();
	int c=8,now=n,nxt;cnt=0;
	if(n<c)
	{
		for(int i=3;i<n;i++)
			ans.push_back({i,n});
		now=n;
		while(now>1)
			now=now/2+(int)(now%2!=0),ans.push_back({n,2});
		return;
	}
	while(1)
	{
		if(now<=c)
			break;
		vis[now]=true;
		a[++cnt]=now;
		nxt=now/c;
		if(now%c!=0)
			nxt+=1;
		now=nxt;
	}
	a[++cnt]=c;
	vis[c]=true;
	for(int i=3;i<n;i++)
	if(!vis[i])
		ans.push_back({i,n});
	for(int i=1;i<cnt;i++)
		ans.push_back({a[i],a[i+1]});
	for(int i=1;i<cnt;i++)
		ans.push_back({a[i],c});
	now=c;
	while(now>1)
		now=now/2+(int)(now%2!=0),ans.push_back({c,2});
}

inline void mainwork()
{
	
}

inline void print()
{
	tot=ans.size();
	printf("%d\n",tot);
	for(p d:ans)
		printf("%d %d\n",d.first,d.second);
}

int main()
{
	int t=1;
	scanf("%d",&t);
	for(cas=1;cas<=t;cas++)
	{
		prework();
		mainwork();
		print();
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/liufengwei1/article/details/114671776