2019.1.15模拟

T1:

给你一个长度为n的序列a,求一个最小n的排列p,使 max ⁡ i = 1 n − 1 ( a [ p [ i ] ]   x o r   a [ p [ i + 1 ] ] ) \max_{i=1}^{n-1}(a[p[i]]~xor~a[p[i+1]]) maxi=1n1(a[p[i]] xor a[p[i+1]])最小。

题解:

不知道为什么想了这么久就是不觉得这题是个贪心。

按照位运算贪心的基本思想,肯定是从高位到低位。

仔细想想不难发现,假设在一位上既有0又有1,那么最优的一种排列方式一定在把0放一边,把1放一边,要求中间的异或和最小,这样就可以求出答案,套路就是用trie。

然后就是字典序最小。

考虑现在把数分成了两个集合,定义边为能接到下一个(双向),两个集合自己是完全图,中间有一些边,中间的边的端点的异或和一定等于ans, 不然就不满足刚才所说。

很容易想到直接贪心的取,判断一个点是否能取的条件是:
一个点x不能取,则x所在点集大小大于1,且另一点集大小大于1,中间的所有边都经过x。

这样下一个可能的决策点也就出来,这个点集的最小和次小,另一点集相邻的最小。

那么用一堆STL维护就可以了,还挺好写的。

T2:

给出长度为n的序列a,求a的最长的异或和为0的子序列。
1<=n,a<=500000

题解:

直接做发现什么性质都没有。

不如补集转换,变成选最少的数,使异或和为S(S=所有数的异或和),
这个就能直接二分,因为如果x个数可行,x+2个数一定可行,当然会TLE

异或可以联想到线性基,不难得到现在的答案<=log n,因为把整个序列建线性基,只用log n个基底就一定可以表示目前所有数的异或空间。

然后就显然了,用FWT优化,不过FWT求一个点的值可以做到O(n),这个后面博客要补。

复杂度 O ( n   l o g   n ) O(n~log~n) O(n log n)
Code(T1):

#include<stdio.h>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#define pp printf
#define ll long long
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define fd(i, x, y) for(int i = x; i >= y; i --)
#define ins insert
using namespace std;

const int N = 3e5 + 5;

int n, a[N];

const int w = 29;

int a2[w + 1], cw[w + 1];

int son[N * (w + 1)][2], tot;
void add(int x) {
	int p = 0;
	fd(i, w, 0) {
		int c = (x & a2[i]) > 0;
		if(!son[p][c]) son[p][c] = ++ tot;
		p = son[p][c];
	}
}
int ff(int x) {
	int p = 0, s = 0;
	fd(i, w, 0) {
		int c = (x & a2[i]) > 0;
		if(son[p][c]) p = son[p][c]; else 
			p = son[p][!c], s += a2[i];
	}
	return s;
}

int g, ans;

set<int> b[2];

int pd(int x) {
	return (a[x] & a2[g]) > 0;
}

map<int, int> c[2];
int siz[2];
ll bs;

int pdq(int x) {
	return siz[pd(x)] > 1 && bs >= 1 && c[!pd(x)][ans ^ a[x]] == bs;
}

map<int, vector<int> > t[2];

void del(int x) {
	bs -= c[!pd(x)][ans ^ a[x]];
	c[pd(x)][a[x]] --;
	siz[pd(x)] --;
	b[pd(x)].erase(x);
	t[pd(x)][a[x]].pop_back();
}

int d[N];

int main() {
	a2[0] = 1; fo(i, 1, w) a2[i] = a2[i - 1] * 2; 
	scanf("%d", &n);
	fo(i, 1, n) scanf("%d", &a[i]);
	fo(i, 1, n)	 {
		fo(j, 0, w) cw[j] += (a[i] & a2[j]) > 0;
	}
	g = -1;
	fd(i, w, 0) if(cw[i] != 0 && cw[i] != n) {
		g = i; break;
	}
	if(g == -1) {
		fo(i, 1, n) pp("%d ", i);
		pp("\n");
		return 0;
	}
	fo(i, 1, n) if(pd(i))
		add(a[i]), b[1].insert(i), c[1][a[i]] ++, siz[1] ++;
	ans = 2e9;
	fo(i, 1, n) if(!pd(i))
		ans = min(ans, ff(a[i])), b[0].insert(i), c[0][a[i]] ++, siz[0] ++;
	fo(i, 1, n) if(pd(i))
		bs += c[0][ans ^ a[i]];
	fd(i, n, 1) t[pd(i)][a[i]].push_back(i);
	int no = 1;
	while(pdq(no)) no ++;
	fo(ii, 1, n) {
		d[ii] = no;
		del(no);
		if(ii == n) continue;
		int y = pd(no);
		int mx = n + 1, cm = n + 1, dm = n + 1;
		if(b[y].size()) {
			mx = *b[y].begin();
			if(pdq(mx)) mx = n + 1;
		}
		if(b[y].size() > 1) {
			cm = *(++ b[y].begin());
			if(pdq(cm)) cm = n + 1;
		}
		if(t[!y][ans ^ a[no]].size()) {
			dm = t[!y][ans ^ a[no]][t[!y][ans ^ a[no]].size() - 1];
			if(pdq(dm)) dm = n + 1;
		}
		int nno = min(mx, min(cm, dm));
		no = min(mx, min(cm, dm));
	}
	fo(i, 1, n) pp("%d ", d[i]);
	pp("\n");
}

Code(T2):

#include<cstdio>
#define low(a) ((a) & -(a))
#define pp printf
#define ul unsigned long long
#define fo(i, x, y) for(int i = x, B = y; i <= B; i ++)
#define ff(i, x, y) for(int i = x; i < y; i ++)
using namespace std;

const int N = 5e5 + 5;

int n, a[N], s;

const int M = 524288;
int b[M]; int c1[M];
int tp;
ul c[M];

void dft(int *a, int tp) {
	int n = 1 << tp;
	for(int h = 1; h < n; h *= 2)
		for(int j = 0; j < n; j += 2 * h) {
			int A, *l = a + j, *r = a + j + h;
			ff(i, 0, h) A = *r, *r = *l - A, *l = *l + A, l ++, r ++;
		}
}

int main() {
	scanf("%d", &n)	;
	fo(i, 1, n) scanf("%d", &a[i]), s ^= a[i];
	if(s == 0) {
		pp("%d\n", n); return 0;
	}
	tp = 19; fo(i, 1, n) b[a[i]] ++;
	dft(b, tp);
	ff(i, 1, 1 << tp) c1[i] = c1[i - low(i)] + 1;
	ff(i, 0, 1 << tp) c[i] = 1;
	for(int ans = 1; ans <= 19; ans ++) {
		ff(i, 0, 1 << tp) c[i] = c[i] * b[i];
		ul sum = 0; ff(i, 0, 1 << tp) sum += c[i] * (c1[i & s] & 1 ? -1 : 1);
		if(sum) {
			pp("%d\n", n - ans);
			return 0;
		}
	}
	pp("0\n");
}
AMESim 2019.1是一款功能强大的系统模拟软件,适用于各种工程学科领域。以下是AMESim 2019.1的安装教程: 第一步,获取安装文件:你可以通过PTC官方网站下载AMESim 2019.1的安装程序。确保你下载的是适合你操作系统的版本。 第二步,解压安装文件:将下载的文件解压到一个你容易访问的位置,比如桌面或者一个新建的文件夹。 第三步,运行安装程序:双击解压后的文件夹中的安装程序,启动安装向导。 第四步,择安装类型:在安装向导中,你可以择要安装的组件和配置。根据你的需求择合适的项。 第五步,接受许可协议:阅读并接受软件的许可协议,然后点击“下一步”。 第六步,择安装位置:在这一步中,你可以择将AMESim安装到默认目录或者择一个自定义的位置。点击“下一步”。 第七步,择启动菜单文件夹:择AMESim的启动菜单文件夹的名称和位置。点击“下一步”。 第八步,设置快捷方式:择是否在桌面上创建AMESim的快捷方式。点击“下一步”。 第九步,确认安装:在这一步中,安装向导会显示你择的安装项的摘要。如果没有问题,点击“安装”开始安装。 第十步,等待安装完成:安装过程可能需要一些时间,请耐心等待。 第十一步,完成安装:一旦安装完成,安装向导会显示“完成”信息。点击“关闭”退出安装向导。 以上是AMESim 2019.1的安装教程。如果你有其他问题或需要更详细的说明,请参考软件的官方文档或寻求官方支持。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值