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

A. 序列

看起来就像辗转相除,果然取个gcd就可以了

code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 1e5 + 55;
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 gcd(int a, int b){return b == 0 ? a : gcd(b, a % b);}
int main(){
	int n = read();
	int ans = read();
	for(int i = 2;i <= n; ++i){
		ans = gcd(ans, read());
	}
	printf("%d\n",ans);
	return 0;
}

B. 任意模数快速插值

还是原来的套路,线段树维护lr的答案,单调栈的同时维护答案

或者写分治

线段树被accoders卡掉了20,被错误的数据范围卡掉了10,可恶

code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define int long long
using namespace std;
const int maxn = 5e5 + 555;
const int mod = 998244353;
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;
}
typedef long long ll;
int a[maxn], n;
struct tree{
	struct node{
		ll smax, smin, val, tmi, tmx;
		node(){
			tmi = tmx = -1;
		}
	}t[maxn << 2 | 1];
	void push_up(int x){
		int ls = x << 1, rs = x << 1 | 1;
		t[x].val = (t[ls].val + t[rs].val) % mod;
		t[x].smax = (t[ls].smax + t[rs].smax) % mod;
		t[x].smin = (t[ls].smin + t[rs].smin) % mod;
	}
	void push_down(int x, int l, int r){
		int ls = x << 1, rs = x << 1 | 1, mid = (l + r) >> 1;
		if(t[x].tmx != -1){
			t[ls].smax = t[x].tmx * (mid - l + 1) % mod;
			t[rs].smax = t[x].tmx * (r - mid) % mod;
			t[ls].tmx = t[rs].tmx = t[x].tmx;
			t[ls].val = t[x].tmx * t[ls].smin % mod;
			t[rs].val = t[x].tmx * t[rs].smin % mod;
			t[x].tmx = -1;
		}
		if(t[x].tmi != -1){
			t[ls].smin = t[x].tmi * (mid - l + 1) % mod;
			t[rs].smin = t[x].tmi * (r - mid) % mod;
			t[ls].tmi = t[rs].tmi = t[x].tmi;
			t[ls].val = t[x].tmi * t[ls].smax % mod;
			t[rs].val = t[x].tmi * t[rs].smax % mod;
			t[x].tmi = -1;
		}
	}
	void modify(int x, int l, int r, int L, int R, int op, int val){
		if(L <= l && r <= R){
			if(op){
				t[x].tmx = val;
				t[x].smax = t[x].tmx * (r - l + 1) % mod;
				t[x].val = t[x].smin * t[x].tmx % mod;
			}else{
				t[x].tmi = val;
				t[x].smin = t[x].tmi * (r - l + 1) % mod;
				t[x].val = t[x].smax * t[x].tmi % mod;
			}
			return;
		}
		push_down(x, l, r);
		int mid = (l + r) >> 1;
		if(L <= mid)modify(x << 1, l , mid, L, R, op, val);
		if(R > mid)modify(x << 1 | 1, mid + 1, r, L, R, op, val);
		push_up(x);
	}
	int query(int x, int l, int r, int L, int R){
		if(L <= l && r <= R)return t[x].val % mod;
		push_down(x, l, r);
		int mid = (l + r) >> 1; ll ans = 0;
		if(L <= mid)ans += query(x << 1, l, mid, L, R);
		if(R > mid)ans += query(x << 1 | 1, mid + 1, r, L, R);
		return ans % mod;
	}
}t;
int stmi[maxn], stmx[maxn], top1, top2, r1[maxn], r2[maxn];
signed main(){
	n = read();
	for(int i = 1; i <= n; ++i)a[i] = read();
	ll ans = 0;
	for(int l = n; l >= 1; --l){
		while(top1 && a[stmi[top1]] > a[l])--top1; 
		r1[l] = top1 ? stmi[top1] - 1: n;
		stmi[++top1] = l;
		t.modify(1, 1, n, l, r1[l], 0, a[l]);
		while(top2 && a[stmx[top2]] < a[l])--top2;
		r2[l] = top2 ? stmx[top2] - 1: n;
		stmx[++top2] = l; 
		t.modify(1, 1, n, l, r2[l], 1, a[l]);
		ans = (ans + t.query(1, 1, n, 1, n)) % mod;
	}
	printf("%lld\n",ans % mod);
	if(ans == 881966332){
		cerr << n << endl;
		// for(int i = 1; i <= n; ++i)cerr << a[i] << " ";
	}
	return 0;
}

C. 快递

dpi,j,k表示在节点i,取快递的状态为j,送快递的状态为k的时间,转移比较显然

不知道为啥当时觉得转移有环,于是用了dij,不过这样好像跑的更快

code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<bitset>
#include<queue>
using namespace std;
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 mp[23][23], n, m, q;
struct node{
	int tim, x, lq, ps;
	node(){}
	node (int tim_, int x_, int lq_, int q_){
		tim = tim_; x = x_; lq = lq_; ps = q_;
	}
	friend bool operator <(const node &x, const node &y){
		return x.tim > y.tim;
	}
};
priority_queue<node>Q;
int dis[23][1025][1025];
bool vis[23][1025][1025];
int l[13],r[13],s[13],t[13];
int main(){
	n = read(), m = read(), q = read();
	memset(mp, 0x3f, sizeof(mp));
	for(int i = 1; i <= m; ++i){
		int u = read(), v = read(), c = read();
		mp[u][v] = min(mp[u][v], c);
	}
	for(int i = 0; i < q; ++i){
		s[i] = read(); t[i] = read();
		l[i] = read(); r[i] = read();
	}
	for(int k = 1; k <= n; ++k)
	 for(int i = 1; i <= n; ++i)
	   for(int j = 1; j <= n; ++j)
	     mp[i][j] = min(mp[i][j], mp[i][k] + mp[k][j]);
	for(int i = 1;i <= n;++i)mp[i][i] = 0;
	int ans = 0;
	memset(dis,0x3f,sizeof(dis));
	dis[1][0][0] = 0;
	Q.push(node(0,1,0,0));
	while(!Q.empty()){
		node x = Q.top(); Q.pop();
		if(vis[x.x][x.lq][x.ps])continue;
		vis[x.x][x.lq][x.ps] = 1;
		int cnt = 0;
		for(int i = x.ps; i; i -= (i & -i))++cnt;
		if(cnt > ans)ans = cnt;
		for(int i = 0; i < q; ++i){
			if((x.lq & (1 << i))){
				if(x.ps & (1 << i))continue;
				int cost = dis[x.x][x.lq][x.ps] + mp[x.x][t[i]];
				if(cost > r[i])continue;
				if(cost < dis[t[i]][x.lq][x.ps | (1 << i)]){
					dis[t[i]][x.lq][x.ps | (1 << i)] = cost;
					Q.push(node(cost, t[i], x.lq, (x.ps | (1 << i))));
				}
			}else{
				int cost = dis[x.x][x.lq][x.ps] + mp[x.x][s[i]];
				if(cost < l[i])cost = l[i];
				if(cost < dis[s[i]][x.lq | (1 << i)][x.ps]){
					dis[s[i]][x.lq | (1 << i)][x.ps] = cost;
					Q.push(node(cost,s[i],(x.lq | (1 << i)),x.ps));
				}
			}
		}
	}
	printf("%d\n",ans);
	return 0;
}

D. 任意模数多项式乘法逆

矩阵快速幂优化递推

然后用光速幂优化一下

不知道为啥mod需要开unsignedlonglong

code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;

const int maxn = 1e6 + 55;
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 f[22], k, q, len;
unsigned long long mod;
struct martix{
	long long mp[23][23];
	int  n, m;
	martix(){
		memset(mp,0,sizeof(mp));
		n = m = 0;
	}
	void print(){
		for(register int i = 1; i <= n; ++i,puts(""))
		 for(register int j = 1; j <= m; ++j)
		  printf("%lld ",mp[i][j]);
		puts("");
	}
}gh[10055], ghn[10055];
martix operator * (martix x, martix y){
	martix z;z.n = x.n, z.m = y.m;
	for(register int i = 1;i <= z.n; ++i){
		for(register int k = 1; k <= x.m; ++k){
			for(register int j = 1;j <= y.m; ++j){
				z.mp[i][j] += x.mp[i][k] * y.mp[k][j];
			}
		}
	}
	for(register int i = 1;i <= z.n; ++i)
		for(register int j = 1;j <= y.m; ++j)
			z.mp[i][j] %= mod;
	return z;
}
void pre_init(){
	ghn[0].n = ghn[0].m = k + 1;
	for(register int i = 1; i <= k + 1; ++i)ghn[0].mp[i][i] = 1;
	martix gz; gz.n = k + 1; gz.m = k + 1;
	for(register int i = 1; i <= k; ++i)gz.mp[i][1] = mod - f[i];
	for(register int i = 1; i <= k + 1; ++i)gz.mp[i][i + 1] = 1;
	ghn[1] = gz;
	for(register int i = 2; i <= len; ++i)ghn[i] = ghn[i - 1] * gz;
	gh[1] = ghn[len];
	gh[0] = ghn[0];
	for(register int i = 2; i <= len; ++i)gh[i] = gh[i - 1] * gh[1];
}
int get_ans(int y){
	long long ans = 0;
	int l1 = y / len, l2 = y % len;
	for(int i = 1; i <= k + 1;  ++i)
	    ans += gh[l1].mp[1][i] * ghn[l2].mp[i][1];
	return ans % mod;
}
int qu[maxn];
signed main(){
	k = read(), q = read(), mod = read();
	f[0] = 1; for(register int i = 1; i <= k; ++i)f[i] = read();
	int mq = 0;
	for(register int i = 1; i <= q; ++i)mq = max(mq, qu[i] = read());
	len = sqrt(mq) + 10;
	pre_init();
	for(register int i = 1; i <= q; ++i){
		printf("%lld\n",get_ans(qu[i]));
	}
	return 0;
}
posted @   Chen_jr  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示