ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[游记]2022年多校冲刺NOIP联训测试8-2022.7.30

2022-08-01 07:31:07  阅读:115  来源: 互联网

标签:ch NOIP int 30 mid 1ll 联训 WR mod


这次好像也不错qwq

A. 序列

B. 任意模数快速插值

C. 快递

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

A. 序列

一眼题面:这不是在模拟更相减损么

然后发现的确是,所以飞快地过了

 

#include<cstdio>
#include<cstring>
#include<string>
#define int long long
#define WR WinterRain
using namespace std;
const int WR=1001000;
int n,ans;
int read(){
    int s=0,w=1;
    char ch=getchar();
    while(ch>'9'||ch<'0'){
        if(ch=='-') w=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        s=s*10+ch-'0';
        ch=getchar();
    }
    return s*w;
}
int gcd(int x,int y){
    if(!y) return x;
    return gcd(y,x%y);
}
signed main(){
    n=read();
    ans=read();
    for(int i=2;i<=n;i++){
        int tmp=read();
        ans=gcd(ans,tmp);
    }
    printf("%lld\n",ans);
    return 0;
}
View Code

 

 

 

B. 任意模数快速插值

这,这名字是唬人的吧(

这种套路做的很多了,直接用单调栈维护出一个数字的支配区间,然后分开处理就行了

也可以用线段树

 

#include<cstdio>
#include<cstring>
#include<string>
#define int long long
#define WR WinterRain
using namespace std;
const int WR=1001000,mod=998244353;
int n,a[WR];
int ans;
int maxx[WR],minn[WR];
int read(){
    int s=0,w=1;
    char ch=getchar();
    while(ch>'9'||ch<'0'){
        if(ch=='-') w=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        s=s*10+ch-'0';
        ch=getchar();
    }
    return s*w;
}
void CDQ(int l,int r){
    if(l==r){
        ans=(ans+a[l]*a[l]%mod)%mod;
        return;
    }
    int mid=(l+r)>>1;
    CDQ(l,mid);
    CDQ(mid+1,r);
    maxx[mid]=minn[mid]=a[mid];
    maxx[mid+1]=minn[mid+1]=a[mid+1];
    for(int i=mid-1;i>=l;i--){
        maxx[i]=max(maxx[i+1],a[i]);
        minn[i]=min(minn[i+1],a[i]);
    }
    for(int i=mid+2;i<=r;i++){
        maxx[i]=max(maxx[i-1],a[i]);
        minn[i]=min(minn[i-1],a[i]);
    }
    int st,ed,res;
    ed=mid;
    for(int i=mid;i>=l;i--){
        while(ed+1<=r&&maxx[i]>=maxx[ed+1]&&minn[i]<=minn[ed+1]) ed++;
        ans=(ans+(maxx[i]*minn[i])%mod*(ed-mid)%mod)%mod;
    }
    st=mid+1;
    for(int i=mid+1;i<=r;i++){
        while(st-1>=l&&maxx[i]>maxx[st-1]&&minn[i]<minn[st-1]) st--;
        ans=(ans+(maxx[i]*minn[i])%mod*(mid-st+1)%mod)%mod;
    }
    st=mid+1,ed=mid;res=0;
    for(int i=mid;i>=l;i--){
        while(ed+1<=r&&maxx[i]>=maxx[ed+1]) ed++,res=(res+minn[ed])%mod;
        while(st<=ed&&minn[i]<=minn[st]) res=(res-minn[st]+mod)%mod,st++;
        ans=(ans+res*maxx[i]%mod)%mod;
    }
    st=mid+1,ed=mid;res=0;  
    for(int i=mid+1;i<=r;i++){
        while(st-1>=l&&maxx[i]>maxx[st-1]) st--,res=(res+minn[st])%mod;
        while(ed>=st&&minn[i]<minn[ed]) res=(res-minn[ed]+mod)%mod,ed--;
        ans=(ans+res*maxx[i]%mod)%mod;
    }
}
signed main(){
    n=read();
    for(int i=1;i<=n;i++) a[i]=read();
    CDQ(1,n);
    printf("%lld\n",ans);
    return 0;
}
单调栈解法

 

#include <bits/stdc++.h>
using namespace std;
#define LL long long
const LL mod = 998244353;
const int maxn = 510005;
LL a[maxn];
int st1[maxn], tp1;
int st2[maxn], tp2;
struct tree
{
    int l, r;
    int len;
    int z1, z2, suml, sumr, val;
} t[maxn * 4];
 
void build(int p, int l, int r)
{
    t[p].l = l, t[p].r = r, t[p].len = r - l + 1;
    if (l == r)
        return;
    int mid = (l + r) >> 1;
    build(p * 2, l, mid);
    build(p * 2 + 1, mid + 1, r);
}
 
void pushdown(int p)
{
    if (t[p].z1)
    {
        t[p * 2].z1 = t[p * 2 + 1].z1 = t[p].z1;
        t[p * 2].suml = 1ll*t[p * 2].len * t[p].z1 % mod;
        t[p * 2 + 1].suml = 1ll*t[p * 2 + 1].len * t[p].z1 % mod;
        t[p * 2].val = 1ll*t[p * 2].z1 * t[p * 2].sumr % mod;
        t[p * 2 + 1].val = 1ll*t[p * 2 + 1].z1 * t[p * 2 + 1].sumr % mod;
        t[p].z1 = 0;
    }
    if (t[p].z2)
    {
        t[p * 2].z2 = t[p * 2 + 1].z2 = t[p].z2;
        t[p * 2].sumr = 1ll*t[p * 2].len * t[p].z2 % mod;
        t[p * 2 + 1].sumr = 1ll*t[p * 2 + 1].len * t[p].z2 % mod;
        t[p * 2].val = 1ll*t[p * 2].suml * t[p * 2].z2 % mod;
        t[p * 2 + 1].val =1ll* t[p * 2 + 1].suml * t[p * 2 + 1].z2 % mod;
        t[p].z2 = 0;
    }
}
 
void changel(int p, int l, int r, LL w)
{
    if (l <= t[p].l && t[p].r <= r)
    {
        t[p].suml = 1ll*t[p].len * w % mod;
        t[p].val = 1ll*w * t[p].sumr % mod;
        t[p].z1 = w;
        return;
    }
    pushdown(p);
    int mid = (t[p].l + t[p].r) >> 1;
    if (l <= mid)
        changel(p * 2, l, r, w);
    if (r > mid)
        changel(p * 2 + 1, l, r, w);
    t[p].val = 1ll*(t[p * 2].val + t[p * 2 + 1].val) % mod;
    t[p].suml = 1ll*(t[p * 2].suml + t[p * 2 + 1].suml) % mod;
    t[p].sumr = 1ll*(t[p * 2].sumr + t[p * 2 + 1].sumr) % mod;
}
 
void changer(int p, int l, int r, int w)
{
    if (l <= t[p].l && t[p].r <= r)
    {
        t[p].sumr = 1ll*t[p].len * w % mod;
        t[p].val = 1ll*t[p].suml * w % mod;
        t[p].z2 = w;
        return;
    }
    pushdown(p);
    int mid = (t[p].l + t[p].r) >> 1;
    if (l <= mid)
        changer(p * 2, l, r, w);
    if (r > mid)
        changer(p * 2 + 1, l, r, w);
    t[p].val = 1ll*(t[p * 2].val + t[p * 2 + 1].val) % mod;
    t[p].suml = 1ll*(t[p * 2].suml + t[p * 2 + 1].suml) % mod;
    t[p].sumr = 1ll*(t[p * 2].sumr + t[p * 2 + 1].sumr) % mod;
}
int l[maxn], r[maxn];
int main()
{
    int n;
    cin >> n;
 
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    build(1, 1, n);
    LL ans = 0;
    for (int i = 1; i <= n; i++)
    {
        while (a[i] >= a[st1[tp1]] && tp1)
            tp1--;
        while (a[i] <= a[st2[tp2]] && tp2)
            tp2--;
        changel(1, st1[tp1] + 1, i, a[i]);
        changer(1, st2[tp2] + 1, i, a[i]);
        LL sum = t[1].val;
        //cout<<t[1].suml<<endl;
        ans += sum;
        ans %= mod;
        st1[++tp1] = i;
        st2[++tp2] = i;
        /*for(int i=1;i<=4*n;i++){
            cout<<t[i].l<<" "<<t[i].r<<" "<<t[i].suml<<" "<<t[i].sumr<<" "<<t[i].z1<<" "<<t[i].z1<<" "<<t[i].val<<endl;
        }
        cout<<endl;*/
    }
    cout << ans;
    return 0;
}
artalter的线段树做法

 

 

 

C. 快递

什么诡异的图上三进制状态压缩 $\operatorname{DP}\cdots$

首先注意到诡异的数据范围,大概率要状压

然后发现有重边,考虑一个邻接矩阵存图, $\operatorname{Floyed}$ 预处理多源最短路

发现每个快递不只有选和不选两种状态,还有一个“在配送”的奇妙状态,状压变成了三进制

由于是三进制,考虑一个 $base$ 的预处理,处理出 $3$ 的幂次方方便计算

枚举状态 $S$ ,如果当前快递还没有选,看一下选的话会不会更优

用当前快递的开始配送时间 $l[i]$ 和从当前位置走到快递点的时间取最大,进行更新

如果当前快递已经选择过了,显然是要直接把它送到

用类似于 $\operatorname{Floyed}$ 的思想,以当前节点为更新点考虑能否更新即可

统计答案时,如果当前的这一位是 $2$ 那么表示快递被送到了, $cnt++$

最后的答案就是 $cnt$ 的最大值

时间复杂度是离谱的 $\Theta(3^qnq)$ ,但注意到玄学的数据范围所以可过

 

#include<cstdio>
#include<cstring>
#include<string>
#define int long long
#define WR WinterRain
using namespace std;
const int WR=200100;
struct Task{
    int s,t,l,r;
}task[WR];
int n,m,q;
int edge[25][25];
int dis[25][25];
int dp[WR][21];
int base[30];
int ans;
int read(){
    int s=0,w=1;
    char ch=getchar();
    while(ch>'9'||ch<'0'){
        if(ch=='-') w=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        s=s*10+ch-'0';
        ch=getchar();
    }
    return s*w;
}
void Floyed(){
    for(int i=1;i<=n;i++) dis[i][i]=0;
    for(int k=1;k<=n;k++){
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
            }
        }
    }
}
signed main(){
    n=read(),m=read(),q=read();
    memset(dis,0x3f,sizeof(dis));
    base[0]=1;
    for(int i=1;i<=q;i++) base[i]=base[i-1]*3;
    for(int i=1;i<=m;i++){
        int u=read(),v=read(),val=read();
        dis[u][v]=min(dis[u][v],val);
    }
    Floyed();
    // for(int i=1;i<=n;i++){
    //     for(int j=1;j<=n;j++){
    //         printf("%lld ",dis[i][j]);
    //     }
    //     printf("\n");
    // }
    memset(dp,0x3f,sizeof(dp));
    dp[0][1]=0;
    for(int i=0;i<q;i++){
        task[i].s=read(),task[i].t=read();
        task[i].l=read(),task[i].r=read();
    }
    for(int S=0;S<base[q];S++){
        for(int i=1;i<=n;i++){
            for(int j=0;j<q;j++){
                int opt=(S/base[j])%3;
                if(!opt){
                    dp[S+base[j]][task[j].s]=min(dp[S+base[j]][task[j].s],
                                                max(dp[S][i]+dis[i][task[j].s],task[j].l));
                }
                if(opt==1&&dp[S][i]+dis[i][task[j].t]<=task[j].r){
                    dp[S+base[j]][task[j].t]=min(dp[S+base[j]][task[j].t],
                                                dp[S][i]+dis[i][task[j].t]);
                }
            }
            if(dp[S][i]!=dp[0][0]){
                int cnt=0;
                for(int j=0;j<=q;j++){
                    if((S/base[j])%3==2) cnt++;
                }
                ans=max(ans,cnt);
            }
        }
    }
    // for(int i=0;i<=base[q]-1;i++){
    //     for(int j=1;j<=n;j++){
    //         if(dp[i][j]==dp[0][0]) printf("- ");
    //         else printf("%lld ",dp[i][j]);
    //     }
    //     printf("\n");
    // }
    printf("%lld\n",ans);
    return 0;
}
View Code

 

 

 

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

 

标签:ch,NOIP,int,30,mid,1ll,联训,WR,mod
来源: https://www.cnblogs.com/WintersRain/p/16538376.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有