2022年多校冲刺NOIP联训测试9

A.理想路径

个人认为这是最难的一道,最后还是褐的\(lxhcr\)大佬的代码,实现细节真的多

不考虑环,直接按照字典序对边排序后扫即可

如果有环,那么环上能到达的所有没访问过的点都不能到达

正解应该需要对询问离线,打树上倍增找第\(k\)

但是数据水,即使在\(accoder\)上也只需要一个火车头就能暴力碾过去

code
#pragma GCC optimize(3)
#pragma GCC optimize(2)
#pragma GCC target("avx")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>

using namespace std;
const int maxn = 2005;
inline int read(){
	int x = 0; char c = getchar();
	while(c < '0' || c > '9')c = getchar();
	do{x = (x << 3) + (x << 1) + (c ^ 48); c = getchar();}while(c >= '0' && c <= '9');
	return x;
}

int n,m,q;
vector<int> v[maxn], pth[maxn][maxn], ls;
int cnt;
bool vis[maxn],now[maxn],flag[maxn];
int root;
void dfs(int x){
	vis[x] = now[x] = 1;
	ls.push_back(x);
	if(cnt == 0)pth[root][x] = ls;
	for(int it : v[x]){
		if(!vis[it]){
			dfs(it);
		}else if(now[it]){
			for(int i = ls.size() - 1; i >= 0; --i){
				if(!flag[ls[i]])flag[ls[i]] = 1, ++cnt;
				if(ls[i] == it)break;
			}
		}
	}
	now[x] = 0;
	cnt -= flag[x];
	ls.pop_back();
}
int main(){
	scanf("%d%d%d",&n,&m,&q);
	for(int i = 1; i <= m; ++i){
		int x,y;
		scanf("%d%d",&x,&y);
		v[x].push_back(y);
	}
	for(int i = 1; i <= n; ++i)sort(v[i].begin(), v[i].end()),v[i].erase(unique(v[i].begin(), v[i].end()), v[i].end());
	for(int i = 1; i <= n; ++i){
		for(int j = 1; j <= n; ++j)vis[j] = 0;
		for(int j = 1; j <= n; ++j)flag[j] = 0;
		root = i;
		dfs(i);
	}
	for(int i = 1; i <= q; ++i){
		int s,t,k;
		scanf("%d%d%d",&s,&t,&k);
		printf("%d\n",(k > pth[s][t].size() ? -1 : pth[s][t][k - 1]));
	}
	return 0;
}

B. 第一题

水题,但是考场时间分配不好,没有切掉,失策失策

不难发现是求\(AB\)为完全平方数的个数

两种做法

一种枚举\(A\),去掉\(A\)的非平方因子,假设得到了\(x\),那么有\(\lfloor\sqrt \frac{n}{x}\rfloor\)\(B\)可以贡献

code
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>

using namespace std;
const int maxn = 2000005;
int n,m,t[maxn],prime[maxn],cnt,mi[maxn];
bool flag[maxn];
int main(){
	scanf("%d%d",&n,&m);
	int mx = max(n, m);
	mi[1] = 1;
	for(int i = 2; i <= mx; ++i){
		if(!flag[i]){
			prime[++cnt] = i;
			mi[i] = i;
		}
		for(int j = 1; j <= cnt && prime[j] * i <= mx; ++j){
			flag[i * prime[j]] = 1;
			mi[i * prime[j]] = prime[j];
			if(i % prime[j] == 0)break;
		}
	}
	int ans = 0;
	n = n + m - mx;
	m = mx;
	for(int i = 1; i <= n; ++i){
		int sum = 1, now = i, ls = 1;
		while(now != 1){
			if(ls % mi[now] == 0)ls/=mi[now];
			else ls*=mi[now];
			now /= mi[now];
		}
		ans += sqrt(m / ls);
	}
	printf("%d\n",ans);
	return 0;
}

另一种枚举\(A\),\(B\)的公共非平方因子,(显然是\(\mu() != 0\)的数),然后有\(\lfloor\sqrt \frac{n}{x}\rfloor \times \lfloor\sqrt \frac{m}{x}\rfloor\)个数可以贡献

code
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>

using namespace std;
const int maxn = 2000005;
int n,m,t[maxn],prime[maxn],cnt,mu[maxn];
bool flag[maxn];
int main(){
	scanf("%d%d",&n,&m);
	int mx = max(n, m);
	mu[1] = 1;
	for(int i = 2; i <= mx; ++i){
		if(!flag[i]){
			prime[++cnt] = i;
			mu[i] = -1;
		}
		for(int j = 1; j <= cnt && prime[j] * i <= mx; ++j){
			flag[i * prime[j]] = 1;
			if(i % prime[j] == 0)break;
			mu[i * prime[j]] = -mu[i];
		}
	}
	int ans = 0;
	n = n + m - mx;
	m = mx;
	for(int i = 1; i <= n; ++i){
		if(mu[i]){
			ans += (int)sqrt(n / i) * (int)sqrt(m / i);
		}
	}
	printf("%d\n",ans);
	return 0;
}

C. 消除贫困

懒得想,直接吉司机

code
#include<cstring>
#include<cstdio>
#include<algorithm>


using namespace std;

const int maxn = 200005;
const int inf = 2147483647;
inline int read(){
	int x = 0; char c = getchar();
	while(c < '0' || c > '9')c = getchar();
	do{x = (x << 3) + (x << 1) + (c ^ 48); c = getchar();}while(c >= '0' && c <= '9');
	return x;
}
int n, a[maxn], q;
struct tree{
	struct node{
		int mi,cm;
		int tmi;
	}t[maxn << 2 | 1];
	void push_up(int x){
		int ls = x << 1, rs = x << 1 | 1;
		t[x].mi = min(t[ls].mi, t[rs].mi);
		t[x].cm = min(t[ls].cm, t[rs].cm);
		if(t[ls].mi < t[x].cm && t[ls].mi != t[x].mi)t[x].cm = t[ls].mi;
		if(t[rs].mi < t[x].cm && t[rs].mi != t[x].mi)t[x].cm = t[rs].mi;
	}
	void built(int x, int l, int r){
		if(l == r){
			t[x].mi = a[l];
			t[x].cm = inf;
			return;
		}
		int mid = (l + r) >> 1;
		built(x << 1, l, mid);
		built(x << 1 | 1, mid + 1, r);
		push_up(x);
	}
	void push_down(int x){
		int ls = x << 1, rs = x << 1 | 1;
		if(t[ls].mi < t[x].tmi){
			t[ls].mi = t[x].tmi;
			t[ls].tmi = t[x].tmi;
		}
		if(t[rs].mi < t[x].tmi){
			t[rs].mi = t[x].tmi;
			t[rs].tmi = t[x].tmi;
		}
		t[x].tmi = 0;
	}
	void cmax(int x, int l, int r, int val){
		if(t[x].mi >= val)return;
		if(t[x].cm > val){
			t[x].mi = val;
			t[x].tmi = val;
			return;
		}
		if(t[x].tmi)push_down(x);
		int mid = (l + r) >> 1;
		cmax(x << 1, l, mid, val);
		cmax(x << 1 | 1, mid + 1, r, val);
		push_up(x);
	}
	void modify(int x, int l, int r, int pos, int val){
		if(l == r){
			t[x].mi = val;
			t[x].cm = inf;
			return;
		}
		if(t[x].tmi)push_down(x);
		int mid = (l + r) >> 1;
		if(pos <= mid)modify(x << 1, l, mid, pos, val);
		else modify(x << 1 | 1, mid + 1, r, pos, val);
		push_up(x);
	}
	void print(int x, int l, int r){
		if(l == r){
			printf("%d ",t[x].mi);
			return;
		}
		if(t[x].tmi) push_down(x);
		int mid = (l + r) >> 1;
		print(x << 1, l, mid);
		print(x << 1 | 1, mid + 1, r); 
	}
}t;
int main(){
	n = read();
	for(int i = 1; i <= n; ++i)a[i] = read();
	t.built(1, 1, n);
	q = read();
	for(int i = 1; i <= q; ++i){
		int op = read();
		if(op == 1){
			int p = read(), x = read();
			t.modify(1, 1, n, p, x);
		}else{
			int x = read();
			t.cmax(1, 1, n, x);
		}
	}
	t.print(1, 1, n);
	return 0;
}

D. 数串

简单的数位\(DP\),但是,模数呢?????

本题考点在于高精,以及卡常众所周知,accoders自带大常数

还有不要卡着空间上界开数组!!!!!!!

本机极限数据在\(0.4s\)左右交上去才能切。。。。。

做法没啥好说的,但是压位高精+极限卡常是真的\(nb\)

code
#pragma GCC optimize(3)
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
typedef unsigned long long ull;
const ull base = 1e18;
struct big{	
	ull a[60];
	big(){memset(a, 0, sizeof(a));}
	friend big operator + (const big &a, const big &b){
		if(a.a[0] == 0)return b;
		if(b.a[0] == 0)return a;
		big c; c.a[0] = max(a.a[0], b.a[0]);
		for(register int i = 1; i <= c.a[0]; ++i)c.a[i] += a.a[i] + b.a[i];
		for(register int i = 1; i <= c.a[0]; ++i){
			c.a[i + 1] += c.a[i] / base;
			c.a[i] = c.a[i] % base;
		}
		if(c.a[c.a[0] + 1])++c.a[0];
		return c;
	}
	big operator *= (int b){
		for(register int i = 1; i <= a[0]; ++i)a[i] = a[i] * b;
		for(register int i = 1; i <= a[0]; ++i){
			a[i + 1] += a[i] / base;
			a[i] %= base;
		}
		if(a[a[0] + 1])++a[0];
		while(a[a[0]]==0 && a[0] > 1)--a[0];
		return *this;
	}
	big operator += (const big &b){
		a[0] = max(a[0], b.a[0]);
		for(register int i = 1; i <= a[0]; ++i)a[i] = a[i] + b.a[i];
		for(register int i = 1; i <= a[0]; ++i){
			a[i + 1] += a[i] / base;
			a[i] %= base;
		}
		if(a[a[0] + 1])++a[0];
		return *this;
	}
	void print(){
		printf("%llu",a[a[0]]);
		if(a[0])for(register int i = a[0] - 1; i; --i)printf("%018llu",a[i]);
		printf("\n");
	}
	void clear(){
		memset(a, 0, sizeof(a));
	}
};
int r[15];
int n, m, k;
big ans1,ans2;
big cnt[2][1029], sum[2][1029], lj;
int main(){
	scanf("%d%d%d",&n,&m,&k);
	for(register int i = 1; i <= m; ++i){
		int a, b; scanf("%d%d",&a,&b);
		r[b] = r[b] | (1 << (a - 1)); 
	}
	int mx = 1 << k;
	for(register int i = 1; i <= k; ++i){
		int zt = (1 << (i - 1));
		cnt[1][zt].a[1] = 1;
		cnt[1][zt].a[0] = 1;
		sum[1][zt].a[1] = i;
		sum[1][zt].a[0] = 1;
	}
	for(register int pos = 1; pos < n; ++pos){
		for(register int zt = 0; zt < mx; ++zt){
			int now = pos & 1;
			if(cnt[now][zt].a[0]){
				sum[now][zt] *= 10;
				lj.clear();
				for(register int j = 1; j <= k; ++j){
					lj += cnt[now][zt];
					if(!(r[j] & zt)){
						int nzt = zt | (1 << (j - 1));
						cnt[1 - now][nzt] += cnt[now][zt];
						sum[1 - now][nzt] += sum[now][zt] + lj;
					}
				}
				cnt[now][zt].clear();
				sum[now][zt].clear();
			}

		}
	}
	int an = n & 1;
	for(register int i = 0; i < mx; ++i){
		ans1 += cnt[an][i];
		ans2 += sum[an][i];
	}
	ans1.print();
	ans2.print();
	return 0;
}
posted @ 2022-08-03 21:33  Chen_jr  阅读(70)  评论(1编辑  收藏  举报