#qbxt国庆水题记#
#day6#
//40 + 20 + 10 = 70
//除了自己垃圾不想说什么了
##Problem A. 最佳进制##
File: divisors.*
Time limit: 1s
Memory limit: 256MB
如今我们最常用的是十进制,据说这是因为人有十根十指。
但事实上这并不是十分方便,10 只有四个因为 1、2、5、10,像
1 1
-
-
3 6
这些分数在十进制下的小数表示就
不是很优美。在这种要求下,12、24 甚至 60 进制会更好一些。
现在想求出不超过 n 的最佳进制数,也就是拥有最多的因子。
Input
第⼀⾏包含⼀个整数 n,(1 ≤ n ≤ 10 16 )。
Output
输出⼀个数 c,表⽰最佳进制数。
Examples
Input Output
100
Subtasks、
60
对于 20% 的数据,n ≤ 100。
对于 40% 的数据,n ≤ 10e5 。
对于 60% 的数据,n ≤ 10e9 。
对于 100% 的数据,k ≤ 10e16 。
根据质因数分解
因数个数 :(a1 +1)*(a2+1)*.....*(an+1)
暴力即可找到n以前拥有最大因数个数的数
//来自[SDOI2005]反素数ant(扩大范围版)
//找了半天规律想错了
#include<iostream>
#include<cstdio>
using namespace std;
#define ll long long
ll n;
int a[100] = {0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41};
ll maxn = 1, ans = 1;
void dfs(int x,ll sum,ll p,int num) {
if( p > ans || ( p == ans && maxn > sum) ) {
ans = p;
maxn = sum;
}
if(x > 13) return;
for(int i = 1; i <= num; i++) {
if(sum * a[x] > n) break;
dfs(x + 1,sum *= a[x],p * (i + 1), i);
}
}
int main() {
freopen("divisors.in","r",stdin);
freopen("divisors.out","w",stdout);
cin>>n;
dfs(1,1,1,100);
cout<<maxn;
return 0;
}
##Problem B. 树##
File: tree.*
Time limit: 1s
Memory limit: 256MB
给出一棵节点数为 n 的有根树,现在需要给每个节点标号,要求对应子树同构的节点标号相同。
若图 G 1 ,G 2 同构,则存在 G 1 点集和 G 2 点集之间的双射 ϕ,满足u → v 是 G 1 中的一条边当且仅当ϕ(u) → ϕ(v) 是 G 2 中的一条边。
Input
第⼀⾏包含⼀个数 n(1 ≤ n ≤ 10 5 ),表子树的点数。
第⼆⾏包含 n − 1 个数,第 i 个数表⽰编号为 i + 1 点的⽗节点编号,满⾜⽗节点的编号⼩于⼦节点,根
节点编号为 1。
Output
包含 n 个数,表⽰节点标号,标号⼤⼩范围在 1 到 n 之间。如果有多种标号,给出字典序最⼩的标
号。
Examples
Input Output
9
1 2 2 1 5 5 7 7
Subtasks
1 2 3 3 4 3 2 3 3
对于 30% 的数据,n ≤ 12。
对于 50% 的数据,n ≤ 100。
对于 100% 的数据,n ≤ 10e5 。
树上Hash(这是什么鬼)
对于每个节点,统计每个儿子的hash值
对哈希值排序,得到此节点的值
暴力递归对拥有不同哈希值的点进行染色
map暴力判断
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn = 100000 + 100;
int n,fa[maxn];
struct edge{
int u,v;
int next;
}e[maxn];
int head[maxn],tot = 0,vis[maxn],dis[maxn];
int read() {
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9') {
if(ch == '-') f = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9') {
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
map < vector<int>, int> q;
void add(int u, int v ) {
e[++tot] = (edge) {u,v,head[u]};
head[u] = tot;
}
int dfs(int x) {
vector <int> tp;
for(int i = head[x]; i; i = e[i].next) {
int v = e[i].v;
tp.push_back(dfs(v));
}
sort(tp.begin(),tp.end());
if(!q[tp]) q[tp] = ++tot;
vis[x] = q[tp];
return vis[x];
}
int main() {
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
n = read();
for(int i = 2; i <= n; i++) {
fa[i] = read();
add(fa[i],i);
}
tot = 0;
dfs(1);
tot = 0;
for(int i = 1; i <= n; i++) {
if(dis[vis[i]] == 0) {
dis[vis[i]] = ++tot;
}
cout<<dis[vis[i]]<<' ';
}
return 0;
}
Hash表版
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<algorithm>
using namespace std;
#define ll long long
const int maxn = 100000 + 100;
const int mod = 1000000007;
const int base = 100000;
int n;
struct edge{
int u,v;
int next;
}e[maxn];
int head[maxn],tot = 0,vis[maxn],dis[maxn];
int read() {
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9') {
if(ch == '-') f = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9') {
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
void add(int u, int v ) {
e[++tot] = (edge) {u,v,head[u]};
head[u] = tot;
}
map<int, int> q;
int dfs(int x) {
int a[1001];
memset(a,0,sizeof(a));
int o = 0;
for(int i = head[x]; i; i = e[i].next) {
int v = e[i].v;
a[++o] = dfs(v);
}
sort(a + 1, a + o + 1);
int tp = 1;
for(int i = 1; i <= o; i++) {
tp = ( (tp * base) % mod + a[i] ) % mod;
}
if(!q[tp]) q[tp] = ++tot;
vis[x] = q[tp];
return vis[x];
}
int main() {
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
n = read();
for(int i = 2; i <= n; i++) {
int l = read();
add(l,i);
}
tot = 0;
dfs(1);
tot = 0;
for(int i = 1; i <= n; i++) {
if(!dis[vis[i]]) {
dis[vis[i]] = ++tot;
}
cout<<dis[vis[i]]<<' ';
}
return 0;
}
##Problem C. 关系##
File: relations.*
Time limit: 1s
Memory limit: 256MB
有一个二元关系 R,R 可以被表示成 n ∗ n 的布尔数组。
现在希望找到长度都为 n 的数组 f 和 g,要求满足 R x,y = 1 当且仅当 f(x) ≤ g(y)。
Input
第一行包含一个整数 n(1 ≤ n ≤ 1000),表⽰数组的大小。
接下来的 n 行表示二元关系 R。
Output
第⼀⾏输出能否找到数组 f 和 g,如果能找到输出 YES,否则输出 NO。−10 9 ≤ f i ,g i ≤ 10 9
第⼆⾏输出 n 个整数,表⽰数组 f。
第三⾏输出 n 个整数,表⽰数组 g 。
Examples
Input Output
3
111
110
100
Subtasks
YES
0 1 2
2 1 0
对于 20% 的数据,n ≤ 10。
对于 50% 的数据,n ≤ 100。
对于 100% 的数据,n ≤ 1000。
可以发现
当R(i,j )= 1时 f[i] <= g[i]
当R(i,j )= 0时 f[i] > g[i]
所以可以建图来解决
定义 u -> v 为 f[u] < g[v]
根据拓扑排序,得到拓扑序,f,g数组就可以用拓扑序来表示
对于NO,找环即可
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define ll long long
const int maxn = 10000 + 100;
int n;
char a[maxn];
struct edge {
int u,v;
int next;
}e[maxn];
int head[maxn], tot = 0, dis[maxn],val[maxn];
void add(int u, int v) {
e[++tot] = (edge){u,v,head[u]};
head[u] = tot;
dis[v]++;
}
void topo() {
queue<int>q;
for(int i = 1; i <= n * 2; i++) if(!dis[i]) q.push(i);
while(!q.empty()) {
int k = q.front();
q.pop();
for(int i = head[k]; i; i = e[i].next) {
int v = e[i].v;
val[v] = max(val[v],val[k] + 1);
dis[v]--;
if(!dis[v]) q.push(v);
}
}
}
int main() {
freopen("relations.in","r",stdin);
freopen("relations.out","w",stdout);
cin>>n;
for(int i = 1; i <= n; i++) {
cin>>a;
for(int j = 1; j <= n; j++) {
if(a[j - 1] == '0') add(i,j + n);
else add(j + n,i);
}
}
topo();
for(int i = 1; i <= n * 2; i++) if(dis[i]) {
cout<<"NO"<<endl;
return 0;
}
cout<<"YES"<<endl;
for(int i = 1; i <= n; i++) cout<<val[i]<<' ';
cout<<endl;
for(int i = 1; i <= n; i++) cout<<val[i + n]<<' ';
cout<<endl;
return 0;
}