牛客练习赛104练习笔记

题目链接

放羊的贝贝

只需要找出最小、最大的横坐标、纵坐标,就可以计算出答案了。

int n, m, k, lx, rx, ly, ry;
int main(){
	n = rd(), m = rd(), k = rd();
	lx = rd(), ly = rd(), rx = rd(), ry = rd();
	while(k--){
		rg int x = rd(), y = rd();
		if(x < lx)lx = x;
		if(x+1 > rx)rx = x+1;
		if(y < ly)ly = y;
		if(y+1 > ry)ry = y+1;
	}
	printf("%lld\n", 2ll*(ry-ly+rx-lx));
	return 0;
}

114514

移项,得到 \((i^{11}-i)(i^{441}-i)i^{10}\equiv 0 \pmod {451\times 4}\)
根据费马小定理,\(a^{p-1}\equiv 1 \pmod p\),那么 \(a^p-a\equiv 0\pmod p\)
由于 \(451\times 4=11\times 41\times 4\) ,所以 \(i^{11}-i\equiv 0\pmod {11}\)
\(i^{441}\equiv i^{41}\times (i^{40})^{10}\equiv i \pmod {41}\),所以 \(i^{441}-i\equiv 0\pmod {41}\)
又由于 \(i^{11}\)\(i\) 奇偶性相同,\(i^{441}\)\(i\) 奇偶性相同,所以 \((i^{11}-i)(i^{441}-i)\) 也是 \(4\) 的倍数。
所以对于任意的 \(i\),都有 \((i^{11}-i)(i^{441}-i)i^{10}\equiv 0 \pmod {451\times 4}\)

int main(){
	cout << rd();
	return 0;
}

1919810

考虑 \(\text{dp}\),设 \(dp_{i,j}\) 为令第数组 \(i\) 位作为子序列的第 \(j\) 位的方案数,那么讨论第 \(j\) 位需要比前一位大还是小,从先前的状态转移过来即可。

cint maxn = 1000010, mod = 1e9+7;
int s[maxn], n, f[8][10], ans;
int main(){
	while(scanf("%1d", &s[++n]) == 1); --n;
	f[1][s[1]] = 1;
	fp(i, 2, n){
		++f[1][s[i]];
		fp(j, 2, 7){
			rg int dp = 0;
			if(j == 2 || j == 4)fp(k, 0, s[i]-1)dp = (dp+f[j-1][k])%mod;
			else fp(k, s[i]+1, 9)dp = (dp+f[j-1][k])%mod;
			f[j][s[i]] = (f[j][s[i]]+dp)%mod;
		}
	}
	fp(i, 0, 9)ans = (ans+f[7][i])%mod;
	printf("%d\n", ans);
	return 0;
}

逃亡的贝贝

二分答案,设当前答案为 \(ans\),将所有 \(w\leq ans\) 的边连上,边权为 \(0\);再将所有 \(\lfloor \frac{114w}{514}\rfloor\leq ans\) 的边脸上,边权为 \(1\) 。再跑一个最短路,如果 \(s\)\(t\) 的最短路小于等于 \(k\) ,就说明这个答案可行。
最短路直接用 \(\text{01bfs}\) 跑,复杂度为 \(\text O((n+m)\log w)\)

cint maxn = 100010, maxm = 200010;
int n, m, s, t, k, dis[maxn];
struct node{ int u, v, w; }nd[maxm];
struct edge{ int to, dis, nxt; }e[maxm<<1];
int head[maxn], cnt;
il void add(cint &u, cint &v, int w){ e[++cnt] = (edge){v, w, head[u]}, head[u] = cnt; }
deque<int> q;
int main(){
	n = rd(), m = rd(), s = rd(), t = rd(), k = rd();
	if(s == t)return puts("0"), 0;
	fp(i, 1, m)nd[i].u = rd(), nd[i].v = rd(), nd[i].w = rd();
	int L = 1, R = 1e9, md, ans = -1;
	while(L <= R){
		md = L+R>>1, memset(head, 0, sizeof head), cnt = 0;
		fp(i, 1, m){
			if(nd[i].w <= md)add(nd[i].u, nd[i].v, 0), add(nd[i].v, nd[i].u, 0);
			else if((114ll*nd[i].w+513)/514 <= md)add(nd[i].u, nd[i].v, 1), add(nd[i].v, nd[i].u, 1);
		}
		while(q.size())q.pop_front();
		memset(dis, 0x3f, sizeof dis), q.push_front(s), dis[s] = 0;
		while(q.size()){
			rg int u = q.front(); q.pop_front();
			if(u == t)break;
			go(u)if(dis[e[i].to] > dis[u]+e[i].dis){
				dis[e[i].to] = dis[u]+e[i].dis;
				if(!e[i].dis)q.push_front(e[i].to);
				else q.push_back(e[i].to);
			}
		}
		if(dis[t] <= k)ans = md, R = md-1;
		else L = md+1;
	}
	if(~ans)printf("%d\n", ans);
	else puts("I really need TS1's time machine again!");
	return 0;
}

炫酷反演魔术

\[\sum_{i=1}^n\sum_{j=1}^n\varphi((a_i,a_j^3)) = \sum_{d=1}^n\varphi(d)\sum_{d|a_i}\sum_{d|a_j^3}[(a_i,a_j^3)=d] \\=\sum_{d=1}^n\varphi(d)\sum_{d|a_i}\sum_{d|a_j^3}\sum_{t|\frac{a_i}{d},t|\frac{a_j^3}{t}}\mu(t) \\=\sum_{d=1}^n\varphi(d)\sum_{t=1}^n\mu(t)\sum_{i=1}^n[td|a_i]\sum_{j=1}^n[td|a_j^3] \\=\sum_{T=1}^n(\sum_{d|T}\mu(d)\varphi(\frac{T}{d}))(\sum_{i=1}^n[T|a_i])(\sum_{j=1}^n[T|a_j^3]) \]

\(f_T=\sum_{d|T}\mu(d)\varphi(\frac{T}{d})\)\(f=\mu*\varphi\),所以 \(f\) 也是积性函数,可以用线筛 \(\text O(n)\) 算出来。
\(g_T=\sum_{i=1}^n[T|a_i]\),这个可以直接 \(\text O(n\ln n)\) 算出来。
\(h_T=\sum_{i=1}^n[T|a_i^3]\),设 \(T=\prod_{i=1}^kp_i^{e_i}\),分别讨论每个质因数。
\(p^e|a^3\),则 \(p^{\lceil\frac{e}{3}\rceil}|a\)。所以记 \(T'=\prod_{i=1}^kp_i^{\lceil\frac{e_i}{3}\rceil}\),则 \(h_T=g_{T'}\)
所以总复杂度就是 \(\text O(n\log n)\)

cint maxn = 300010;
int n, a[maxn];
int pri[maxn], cnt, mu[maxn], phi[maxn], f[maxn], v[maxn], vk[maxn];
int c[maxn], g[maxn], h[maxn];
LL ans;
int main(){
	n = rd(), phi[1] = f[1] = 1;
	fp(i, 1, n)a[i] = rd(), ++c[a[i]];
	fp(i, 2, n){
		if(!v[i])v[i] = i, mu[i] = -1, phi[i] = i-1, f[i] = i-2, vk[i] = i, pri[++cnt] = i;
		for(rg int j = 1; j <= cnt && pri[j]*i <= n; ++j){
			v[i*pri[j]] = pri[j];
			if(i%pri[j] == 0){
				phi[i*pri[j]] = phi[i]*pri[j], vk[i*pri[j]] = vk[i]*pri[j];
				if(vk[i] == i)f[i*pri[j]] = phi[i*pri[j]]-phi[i];
				else f[i*pri[j]] = f[i/vk[i]]*f[vk[i*pri[j]]];
				break;
			}
			phi[i*pri[j]] = pri[i]*phi[pri[j]], mu[i*pri[j]] = -mu[i];
			vk[i*pri[j]] = pri[j], f[i*pri[j]] = f[i]*f[pri[j]];
		}
	}
	fp(i, 1, n)for(rg int j = i; j <= n; j += i)g[i] += c[j];
	fp(i, 1, n){
		rg int x = i, res = 1;
		while(x > 1){
			rg int k = 0, p = v[x];
			while(x%p == 0)x /= p, ++k;
			fp(i, 1, (k+2)/3)res *= p;
		}
		h[i] = g[res];
	}
	fp(i, 1, n)ans += 1ll*f[i]*h[i]*g[i];
	printf("%lld\n", ans);
	return 0;
}

树剖分剖树

学到了……随机化算法,随机生成一个序列 \(v\),将 \(w_i\) 映射为 \(v_{w_i}\) ,然后将某一段长度为 \(k\) 的序列异或起来,若结果等于 \(v_1\bigotimes v_2...\bigotimes v_k\) ,那就认为它是长度为 \(k\) 的排列。出错率不会算,反正能过
对于每棵子树,记录一下深度为 \(\text{dep}\),到根节点的异或和为 \(\text{val}\) 的点的个数,合并的时候启发式合并,同时计算答案即可。用 \(\text{map}\) 来记录的话复杂度就是 \(\text O(n\log^2n)\)

cint maxn = 300010;
int n, k, w[maxn], val[maxn], res;
int sum[maxn], dep[maxn];
LL ans;
map< pair<int, int>, int > mp[maxn];
struct edge{ int to, nxt; }e[maxn<<1];
int head[maxn], cnt;
il void add(cint &u, cint &v){ e[++cnt] = (edge){ v, head[u] }, head[u] = cnt; }
void dfs(int u, int pre){
	dep[u] = dep[pre]+1, sum[u] = sum[pre]^w[u];
	++mp[u][make_pair(dep[u], sum[u])];
	go(u)if(e[i].to != pre){
		rg int v = e[i].to;
		dfs(v, u);
		if(mp[u].size() < mp[v].size())swap(mp[u], mp[v]);
		for(auto &x : mp[v]){
			pair<int, int> tmp = x.first;
			pair<int, int> des = make_pair(k-tmp.first-1+2*dep[u], res^tmp.second^w[u]);
			if(mp[u].count(des))ans += 1ll*mp[u][des]*x.second;
		}
		for(auto &x : mp[v]){
			if(x.first.first-dep[u] >= k)continue;
			mp[u][x.first] += x.second;
		}
	}
}
int main(){
	srand(20040127);
	n = rd(), k = rd();
	fp(i, 1, n)val[i] = rand()*rand();
	fp(i, 1, n)w[i] = val[rd()];
	fp(i, 2, n){
		rg int u = rd(), v = rd();
		add(u, v), add(v, u);
	}
	fp(i, 1, k)res ^= val[i];
	dfs(1, 0), printf("%lld\n", ans);
	return 0;
}
posted @ 2022-10-23 20:23  修电缆的建筑工  阅读(35)  评论(0编辑  收藏  举报