qbxt国庆水题记day6

来源:互联网 发布:定性与定量数据区别 编辑:程序博客网 时间:2024/05/13 19:41

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 longll 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 longconst 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 longconst 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;}