****
因为是刚听完课所以想把思路记下来,有一些其实也是一知半解的,如果有dalao可以帮忙讲解那真是再感谢不过了。
*****还有为什么我画图这么丑,哇的一下哭出声*******
Problem A. 最佳进制
如今我们最常用的是十进制,据说这是因为人有十根手指。
但事实上这并不是十分方便,10 只有四个因子 1、2、5、10,
像 1/3、1/6 这些分数在十进制下的十数表示就
不是很优美。在这种要求下,12、24 甚至60 进制会更好一些。
现在想求出不超过 n 的最佳进制数,也就是拥有最多的因子。
Input
第一包含一个整数 n,(1 ≤ n ≤ 1e16)。
Output
输出一个数 c,表示最佳进制数。
Examples
Input
100
Output
60
Subtasks
对于20% 的数据,n<=100。
对于40% 的数据,n<=1e5。
对于60% 的数据,n<=1e9。
对于100% 的数据,k<=1e6。
注:若有多个解,输出最小的那个
解析:
求因子最多的数
一个大多数人都知道但我不知道的关系:x=∏Pi^ai //∏为累乘符号
即x为多个质因数(Pi)的ai次方的乘积
则这个数所有的因子个数ans=∏(ai+1)
例:12=(2^2)*(3^1)
还有就是如果ai是x的因子,则a1~a(i-1)一定都为x的因子(这里不是很能理解,如果这个数是质数咋办???求告知) 即a1>=a2>=a3….>=an
由于题目范围为1e16,且2*3*5*……*47>1e16,则分解因数只需到47
另外就是如果x|y,则x的每个质因数一定也为y的质因数,且幂次一定比在y的幂次小
又因为(2^3)*(3^2)与(2^2)*(3^3)的因子数是一样的,因此最好让小的质因子的幂次更高
下面就是愉快的代码时间了
#include
#include
#include
#include
using namespace std;
long long n, maxd, ans;
int prime[] = {0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47};
void dfs(int x, long long sum, long long nowd, long long Limit) {
if (nowd > maxd || (nowd == maxd && sum < ans))
maxd = nowd, ans = sum;
if (x > 11) return;
for (int i = 1; sum * prime[x] <= n && i <= Limit; i++)
dfs(x + 1, sum *= prime[x], nowd * (i + 1), i);
}
int main()
{
freopen("divisors.in","r",stdin);
freopen("divisors.out","w",stdout);
cin >> n;
ans = 1;
if (n > 1) dfs(1, 1, 1, 1e9);
cout << ans << endl;
return 0;
}
Problem B. 树
File: tree.*
Time limit: 1s
Memory limit: 256MB
给出一棵节点数为n 的有根树,现在需要给每个节点标号,要求对应子树同构的节点标号相同。
若图G1,G2 同构,则存在G1 点集和G2 点集之间的双射ϕ,满足u ->v 是G1 中的一条边当且仅当
ϕ(u) ! ϕ(v) 是G2 中的一条边。
Input
第一包含一个数n(1<=n<=105),表示树的点数。
第二行包含n - 1 个数,第i 个数表示编号为i + 1 点的父节点编号,满足父节点的编号小于子节点,根
节点编号为1。
Output
一行包含n 个数,表示节点标号,标号大小范围在1 到n 之间。如果有多种标号,给出字典序最小的标
号。
Examples
Input
9
1 2 2 1 5 5 7 7
Output
1 2 3 3 4 3 2 3 3
Subtasks
对于30% 的数据,n<=12。
对于50% 的数据,n<=100。
对于100% 的数据,n<=105。
解析:
一道”简单的”Hash题
先说一下啥叫同构:即子树的节点和构成相同(即相对位置相同)
在下图中,4/5/7/8/9全为叶子结点,则他们位置相同;2/6都各有两个子节点,则它们位置相同;而1/3的子节点各不相同,应处于不同的位置(位置也即最后要求的节点编号)
另外,子树是可以旋转的,也就是说下面的这两棵树也是同构的
下面就开始Hash了
由于是否同构看到是子树,因此我们从叶子到根Hash,Hash值相同的则为同构
在上图中,令4/7/8/9/10/11都为空集,也就是[ ],则5/6均为[1,1],2/3为[1,2]/[2,1](一样的),1为[3,3].
Hash完可以发现4/7/8/9/10/11的值是一样的,5/6的值一样,2/3的值一样,1自己一个值
具体如何Hash呢?即将每个数看成n进制的,然后将它们化为10进制,例n进制下的12为10进制下的1*n+2
当所有节点的Hash值都求完后,我们设一个计数器cnt,每当出现一个新数,就cnt++,然后把cnt作为标号赋给当前值,若此Hash值之前已经出现,则直接输出
具体实现可用map函数,怎么写在代码里就不多说了
#include
#include
#include
#include
#include
#include
Problem C. 关系
File: relations.*
Time limit: 1s
Memory limit: 256MB
有一个二元关系R,R 可以被表示成n*n 的布尔数组。
现在希望找到长度都为n 的数组f 和g,要求满足Rx,y = 1 当且仅当f(x)<=g(y)。
Input
第一行包含一个整数n(1<=n<=1000),表示数组的大小。
接下来的n 行表示二元关系R。
Output
第一行输出能否找到数组f 和g,如果能找到输出YES,否则输出NO。-1e9<=fi; gi<=109
第二行输出n 个整数,表示数组f。
第三行输出n 个整数,表示数组g 。
Examples
Input
3
111
110
100
Output
YES
0 1 2
2 1 0
Subtasks
对于20% 的数据,n<=10。
对于50% 的数据,n<=100。
对于100% 的数据,n<=1000。
解析:
Zcc dalao说看到这个就应该想到图啊(我没想到但我记住了)
如果a<=b,b<=c,则一定有a<=c
即R[a][b]=1,R[b][c]=1--->>R[a][c]=1若不满足此条件则输出”NO”
我们另R[a][b]=1当且仅当f[a]>g[b]时(为了建图方便)
如果R[x][y]=1,则连一条x到y+n(为了方便输出)
同理,如果R[x][y]=0,则连一条x到y+n
则可得到一个DAG(有向无环图)[因为a<b,b<c,c<a不可能同时成立,则应为DAG]
之后就拓扑排序求值啦(第几个拿到则为几)
代码
#include
#include
#include
#include
#include
#include
using namespace std; int f[1005], g[1005], cnt[1005], n; int cmp(int i, int j) { if (cnt[i] == cnt[j]) return (i < j); return cnt[i] < cnt[j]; } int main() { string s[1005]; vector
v; freopen("relations.in", "r", stdin); freopen("relations.out", "w", stdout); cin >> n; for(int i=0; i
> s[i]; v.push_back(i); cnt[i] = 0; for(int j=0; j
s[y][j]) { correct = false; break; } if(!correct) break; } for(int i=0; i