2022年多校冲刺NOIP联训测试8
A. 序列
看起来就像辗转相除,果然取个就可以了
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. 任意模数快速插值
还是原来的套路,线段树维护的答案,单调栈的同时维护答案
或者写分治
线段树被卡掉了,被错误的数据范围卡掉了,可恶
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. 快递
设表示在节点,取快递的状态为,送快递的状态为的时间,转移比较显然
不知道为啥当时觉得转移有环,于是用了,不过这样好像跑的更快
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. 任意模数多项式乘法逆
矩阵快速幂优化递推
然后用光速幂优化一下
不知道为啥需要开
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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】