• [LOJ#2328]「清华集训 2017」避难所


    [LOJ#2328]「清华集训 2017」避难所

    试题描述

    “B君啊,你当年的伙伴都不在北京了,为什么你还在北京呢?”
    
    “大概是因为出了一些事故吧,否则这道题就不叫避难所了。”
    
    “唔,那你之后会去哪呢?”
    
    “去一个没有冬天的地方。”
    

    对于一个正整数 (n),我们定义他在 (b) 进制下,各个位上的数的乘积为 (p = F(n, b))

    比如 (F(3338, 10) = 216)

    考虑这样一个问题,已知 (p)(b),求最小的 (n) 满足 (p = F(n, b))

    这是一个非常有趣的问题,对于一些 (b) 来说,我们可以贪心来做,比如如果 (b=10, p=216)

    我们可以从 (b-1)(2) 试除,直到 (p)(1) 为止,答案是 (389),可以验证 (389) 是满足 (p = F(n, b)) 最小的 (n)

    但是对于一些进制 (b),是不能用贪心做的,比如 (b = 9, p = 216)。使用贪心得到的解是 (3338),而最优解是 (666)。(均为 (9) 进制下的。)

    本题便是在给定进制 (b) 的情况下,举出一个这样的反例,或指出这样的反例不存在。

    由于计算资源所限,反例中所有数字的乘积不能超过 (10^{18})。如果最小的反例中所有数字的乘积超过了 (10^{18}),那么也应该输出 (-1)

    输入

    从标准输入读入数据。

    第一行一个整数 (t),表示一共有 (t) 组数据。

    接下来每行一个整数 (b),表示进制。

    输出

    输出到标准输出。

    如果不存在反例,输出一行一个整数 (-1)

    如果存在反例,首先输出一个整数 (k),表示反例 (n) 的位数,接下来在同一行输出 (k) 个十进制整数,表示任意一个反例的最优解。

    输入示例

    3
    8
    9
    10
    

    输出示例

    -1
    3 6 6 6
    -1
    

    数据规模及约定

    对于第 (1) 个测试点,分值为 (30)(1 leq b leq 32)

    对于第 (2) 个测试点,分值为 (40)(1 leq b leq 100)

    对于第 (3) 个测试点,分值为 (30)(1 leq t leq 200, 1 leq n leq 100000)

    题解

    这题。。。woc居然是个打表。。。

    当然只有 (b le 130) 的时候需要打表,剩下的可以构造。

    (b > 130) 时,实验证明都可以用三个相同的数字举出反例,令这相同的三个数字值为 (p_1p_2)(这是两个数的乘积),那么需要让他的贪心翻车,就要想方设法让贪心搞出 (4) 位数来,即 (p_2, p_2, p_2, p_1^3) 这样的一个四位数。

    那么只需要满足几个条件:

    • (p_1, p_2) 都是素数

    • (p_1p_2 < b)

    • (p_1^3 < b)

    • (p_2^2 ge b)

    • (p_1p_2 < p_1^3)

    下面是打表程序:

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    using namespace std;
    #define rep(i, s, t) for(int i = (s); i <= (t); i++)
    #define dwn(i, s, t) for(int i = (s); i >= (t); i--)
    
    int read() {
    	int x = 0, f = 1; char c = getchar();
    	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    	return x * f;
    }
    
    #define maxn 100010
    #define LL long long
    
    int prime[maxn], cp;
    bool vis[maxn];
    void init() {
    	rep(i, 2, maxn - 1) {
    		if(!vis[i]) prime[++cp] = i;
    		for(int j = 1; j <= cp && i * prime[j] < maxn; j++) {
    			vis[i*prime[j]] = 1;
    			if(i % prime[j] == 0) break;
    		}
    	}
    	return ;
    }
    
    int ans, now[maxn], sol[maxn];
    void dfs(int up, int x, int cur) {
    	if(ans <= cur) return ;
    	if(x == 1){ ans = cur; rep(i, 1, cur) sol[i] = now[i]; return ; }
    	dwn(i, up, 2) if(x % i == 0) now[cur+1] = i, dfs(i, x / i, cur + 1);
    	return ;
    }
    
    int main() {
    	freopen("list.txt", "w", stdout);
    	
    	init();
    	
    	int reach = 140;
    	printf("char Ans[%d][50] = {", reach);
    	rep(b, 1, reach) {
    		int x = 1; bool ok = 0;
    		while(x <= 1000000) {
    			int tmp = ++x;
    			// greedy
    			int cnt = 0;
    			dwn(i, b - 1, 2) if(tmp % i == 0) tmp /= i, i++, cnt++;
    			// force
    			ans = cnt;
    			dfs(b - 1, x, 0);
    			if(ans < cnt) {
    				sort(sol + 1, sol + ans + 1);
    				printf(""%d ", ans);
    				rep(i, 1, ans) printf("%d%c", sol[i], i < ans ? ' ' : '"');
    				ok = 1;
    				break;
    			}
    		}
    		if(!ok) printf(""-1"");
    		printf("%s", b < reach ? ", " : "};
    ");
    	}
    	
    	return 0;
    }
    

    下面是 AC 程序:

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    using namespace std;
    #define rep(i, s, t) for(int i = (s); i <= (t); i++)
    #define dwn(i, s, t) for(int i = (s); i >= (t); i--)
    
    int read() {
    	int x = 0, f = 1; char c = getchar();
    	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    	return x * f;
    }
    
    #define maxn 100010
    #define LL long long
    
    char Ans[140][50] = {"-1", "-1", "-1", "-1", "-1", "-1", "-1", "-1", "3 6 6 6", "-1", "-1", "-1", "3 9 10 10", "3 9 10 10", "3 9 10 10", "-1", "3 12 14 14", "3 12 14 14", "3 10 15 15", "3 10 15 15", "3 10 15 15", "3 10 15 15", "3 10 15 15", "3 10 15 15", "3 10 15 15", "3 15 18 18", "3 15 18 18", "3 14 20 21", "3 15 21 21", "3 15 21 21", "3 15 21 21", "3 15 21 21", "3 15 21 21", "3 15 21 21", "3 15 21 21", "3 21 21 21", "3 21 21 21", "3 21 21 21", "3 21 21 21", "3 21 21 21", "3 21 21 21", "3 21 21 21", "3 21 21 21", "3 21 21 21", "3 21 21 21", "3 21 21 21", "3 21 21 21", "3 21 21 21", "3 21 21 21", "3 22 33 35", "3 22 33 35", "3 22 33 35", "3 22 33 35", "3 22 33 35", "3 22 33 35", "3 26 35 39", "3 26 35 39", "3 26 35 39", "3 26 35 39", "3 26 35 39", "3 26 35 39", "3 26 35 39", "3 26 35 39", "3 26 35 39", "3 26 35 39", "3 22 44 49", "3 22 44 49", "3 22 44 49", "3 22 44 49", "3 22 44 49", "3 22 44 49", "3 22 44 49", "3 22 44 49", "3 22 44 49", "3 22 44 49", "3 22 44 49", "3 22 44 49", "3 26 49 52", "3 26 49 52", "3 26 49 52", "3 26 49 52", "3 26 49 52", "3 26 49 52", "3 26 49 52", "3 26 49 52", "3 26 49 52", "3 26 49 52", "3 26 49 52", "3 26 49 52", "3 26 49 52", "3 26 49 52", "3 33 55 55", "3 33 55 55", "3 33 55 55", "3 33 55 55", "3 33 55 55", "3 33 55 55", "3 33 55 55", "3 33 55 55", "3 33 55 55", "3 33 55 55", "3 33 55 55", "3 33 55 55", "3 33 55 55", "3 33 55 55", "3 33 55 55", "3 33 55 55", "3 33 55 55", "3 33 55 55", "3 33 55 55", "3 33 55 55", "3 33 55 55", "3 33 55 55", "3 33 55 55", "3 33 55 55", "3 33 55 55", "3 33 55 55", "3 33 55 55", "3 33 55 55", "3 33 55 55", "3 33 55 55", "3 33 65 65", "3 33 65 65", "3 33 65 65", "3 33 65 65", "3 33 65 65", "3 33 65 65", "3 33 65 65", "3 33 65 65", "3 33 65 65", "3 33 65 65", "3 33 65 65", "3 33 65 65", "3 33 65 65", "3 33 65 65", "3 33 65 65", "3 33 65 65", "3 33 65 65", "3 33 65 65", "3 33 65 65"};
    
    int prime[maxn], cp;
    bool vis[maxn];
    void init() {
    	rep(i, 2, maxn - 1) {
    		if(!vis[i]) prime[++cp] = i;
    		for(int j = 1; j <= cp && i * prime[j] < maxn; j++) {
    			vis[i*prime[j]] = 1;
    			if(i % prime[j] == 0) break;
    		}
    	}
    	return ;
    }
    
    int main() {
    	init();
    	
    	int T = read();
    	while(T--) {
    		int b = read();
    		if(b > 140) {
    			bool ok = 0;
    			for(int i = 1; i <= cp && prime[i] <= b; i++) {
    				for(int j = 1; j <= cp && prime[j] <= b; j++) {
    					int p1 = prime[i], p2 = prime[j];
    					if((LL)p1 * p2 < b && (LL)p1 * p1 * p1 < b && (LL)p2 * p2 >= b && (LL)p1 * p1 > p2) {
    						printf("3 %lld %lld %lld
    ", (LL)p1 * p2, (LL)p1 * p2, (LL)p1 * p2);
    						ok = 1; break;
    					}
    				}
    				if(ok) break;
    			}
    			if(!ok) puts("-1");
    		}
    		else puts(Ans[b-1]);
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    第123讲:Hadoop集群管理之Namenode目录元数据结构详解学习笔记
    看待类和对象/C++的访问修饰符的作用
    c++之 reference vs point转
    关于 《C++网络编程+卷1+运用ACE和模式消除复杂性》的源码及例子
    C++之 new转
    第二次作业案例分析
    第一次作业四则运算
    【博客观后感】
    hello
    hlt指令
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/8046442.html
Copyright © 2020-2023  润新知