qbxt国庆水题记day6

#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;
}	
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值