杭电多校2020第二场

1001-Total Eclipse

题意:
n座城市,m条路,每个城市有一盏亮度为bi的灯,每次可以选择一个联通块让联通块上所有城市k(k的数量要尽可能大)的灯亮度减1,但灯亮度为0的城市不能算入联通块中,问让全部城市的灯亮度变为0的最小次数是多少。

题解:
(这题偷偷改过题面也没发通知==,加了k要尽量大这句话)
我们可以找某个联通块上亮度最小的城市,一直减直到该城市亮度为0,然后划分为更小的联通块,一直反复即可让所有城市的灯亮度为0。(但是我不会)
反过来做就比较简单,先假设所有点都是孤立的,sum = ∑ i = 1 n b i \sum_{i=1}^n bi i=1nbi,将所有点按照bi从大到小排序,建立一根有根树,枚举所有的城市i,遍历与 i 连接的城市 j ,如果 j 遍历过并且与i的树根父亲不同,那么合并 i 与 j,并将 j 的树根父亲赋值给 i 的树根父亲,由于 i 城市与 j 城市是互相联通并且 bi <= bj,在将 j 城市灯亮度变为0之前 i 城市灯亮度已经为0,所以 i 城市亮度计算重复,sum -= bi。(PS:并查集需要使用路径压缩)

AC_CODE:

const int maxn = 4e6+5;

struct node{
	int value;
	int index;	
}k[maxn];

VI G[maxn];
bool vis[maxn];
int fa[maxn];

int get_father(int x) {
	if(x == fa[x]) return x;
	return fa[x] = get_father(fa[x]);
}

void merge(int x, int y) {
	x = get_father(x);
	y = get_father(y);
	if(x != y) {
		fa[x] = y;
	}
}

void solve(){
	int n,m;
	R(n,m);
	ll sum = 0;
	for(int i=1; i<=n; ++i) {
		R(k[i].value);
		k[i].index = i;
		G[i].clear();
		vis[i] = false;
		fa[i] = i;
		sum += k[i].value;
	}
	sort(k+1,k+1+n,[](node x, node y){return x.value > y.value;});
	for(int i=1; i<=m; ++i) {
		int u,v;
		R(u,v);
		G[u].PB(v);
		G[v].PB(u);
	}
	for(int i=1; i<=n; ++i) {
		for(auto x: G[k[i].index]) {
			if(vis[x]) {
				int root = get_father(x);
				if(root != get_father(k[i].index)) {
					merge(x,k[i].index);
					sum -= k[i].value;
				}
			}
		}
		vis[k[i].index] = true;
	}
	W(sum);
}

1006-The Oculus

题意:
设Fi为斐波那契数列,bi为非0即1的数组,对于任意一个正整数x,都有以下性质:

b1×F1 + b2×F2 ++ bn×Fn = x.
bn = 1.
bi * bi+1 = 0.(即不存在bi=1并且bi+1=1)

现在给出三个数a,b,c,这三个数由b1×F1 + b2×F2 + ⋯ + bn×Fn = x表示,并且满足c=a*b,现在将c某一项bi=1修改为0,询问i是多少。

题解:
思路是计算出a×b-c的值,然后判断与哪一项斐波那契数列的值相等。
由于这题给定的数据范围为1e6,所以我们必须求出0到1e6中所有斐波那契数列的值,但在计算中间会爆long long,所以需要用到哈希,取一个尽可能大的模数,在这道题里面一些比较常用的大质数(如998244353,1e9+7)都不能用,因为得换一个更大的模数,因为使用到大模数,会导致a×b爆long long,所以需要使用快速乘。

AC_CODE:

const ll mod = 5000000002453;
ll qmul(ll a,ll b){ ll r=0; while(b){ if(b&1) r=(r+a)%mod; a=(a+a)%mod; b>>=1; } return r;}
const int maxn = 4e6+5;
ll f[maxn];

/*
struct node{
	
}k[maxn];
*/

void init() {
	f[0] = 1LL;
	f[1] = 1LL;
	f[2] = 2LL;
	for(int i=3; i<=maxn-1; ++i) f[i] = (f[i-1] + f[i-2]) % mod;
}

void solve(){
	int n;
	R(n);
	ll a(0),b(0),c(0);
	for(int i=1; i<=n; ++i) { 
		int k; R(k);
		if(k) a = (a + f[i]) % mod;
	}
	R(n);
	for(int i=1; i<=n; ++i) { 
		int k; R(k);
		if(k) b = (b + f[i]) % mod;
	}
	R(n);
	for(int i=1; i<=n; ++i) { 
		int k; R(k);
		if(k) c = (c + f[i]) % mod;
	}
	ll d = (qmul(a,b) % mod - c + mod) % mod;
//	assert(d > 0);
//	debug(a,b,c,d);
	FOR(i,1,maxn-1) {
		if(d % mod == f[i]) {
			W(i);
			return;
		}
	}
}

你可能感兴趣的:(算法)