首页 > 其他分享 >CSP 模拟 1

CSP 模拟 1

时间:2024-07-12 21:52:15浏览次数:11  
标签:ch int res long zc && CSP 模拟

T1 最短路(P2966 [USACO09DEC] Cow Toll Paths G)

考察 Floyd 的理解,Floyd 本身是 \(O(n^3)\) 的空间复杂度。\(f_{k,i,j}\) 表示只经过前 \(k\) 个点(不包含 \(i,j\)),从 \(i\) 到 \(j\) 的最短距离。
发现这个 \(k\) 的顺序是没有任何影响的。
所以以点权的顺序枚举 \(k\),这样保证算的路径中的最大值都是已知的,直接 Floyd 就行了。

点击查看代码
#include<bits/stdc++.h>
#define int long long
typedef long long ll;
typedef unsigned long long ull;
inline int read(){char ch=getchar();int x=0,f=1;for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);return x*f;}
const int N=310;
int n,f[N][N],m,w[N],q,dis[N][N];
std::pair<int,int>temp[N];
signed main(){
    // freopen("path.in","r",stdin);freopen("path.out","w",stdout);
    std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);
    n=read(),m=read();q=read();
    memset(f,0x3f,sizeof(f));memset(dis,0x3f,sizeof(dis));
    for(int i=1;i<=n;++i)w[i]=temp[i].first=read(),temp[i].second=i,dis[i][i]=0;
    for(int i=1;i<=m;++i){
        int u=read(),v=read();
        dis[u][v]=dis[v][u]=std::min(dis[u][v],read());
    }
    std::sort(temp+1,temp+n+1);
    for(int z=1,k=temp[z].second;z<=n;++z,k=temp[z].second){
        for(int i=1;i<=n;++i)
            for(int j=1;j<=n;++j)
                dis[i][j]=std::min(dis[i][j],dis[i][k]+dis[k][j]),f[i][j]=std::min(f[i][j],dis[i][j]+std::max(std::max(w[i],w[k]),w[j]));
    }
    for(int i=1;i<=q;++i){
        int u=read(),v=read();
        std::cout<<(f[u][v]==f[0][0]?-1:f[u][v])<<'\n';
    }
}

T2 方格取数(P3474 [POI2008] KUP-Plot purchase)

先特判不可能合法的点和一定合法的点,然后就只剩下权值在 \([1,k-1]\) 中的点,这时考虑找到一个子矩阵的权值和大于 \(k\),则此时一定有解。

  • 考虑这个子矩阵的从上到下每一行,如果这一行的权值和大于 \(k\),那么答案属于这一行,因为这时的所有点权小于 \(k\),所以可以一个一个删使这一行达到合法范围。
  • 如果这一行权值小于 \(k\),删去这一行后继续往下找。以此类推,直到剩下的矩阵权值和在合法范围中。

具体来说,处理出每一个点能向上扩展的最大高度,然后单调栈找最大矩阵即可,因为权值是正整数,所以这样一定可以扫描到权值和最大的矩阵,找到之后就执行上述操作即可。

点击查看代码
#include<bits/stdc++.h>
#define int long long
typedef long long ll;
typedef unsigned long long ull;
inline int read(){char ch=getchar();int x=0,f=1;for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);return x*f;}
const int N=2e3+10;
int n,k,a[N][N],s[N][N],l[N][N],q[N],head,tail,wi[N],sum[N][N];
inline int ask(int i,int j,int x,int y){
    return sum[x][y]-sum[i-1][y]-sum[x][j-1]+sum[i-1][j-1];
}
signed main(){
    // freopen("matrix.in","r",stdin);freopen("matrix.out","w",stdout);
    std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);
    k=read(),n=read();
    for(int i=1;i<=n;++i)for(int j=1;j<=n;++j){
        a[i][j]=read();
        if(a[i][j]>=k&&a[i][j]<=2*k){std::cout<<j<<' '<<i<<' '<<j<<' '<<i<<'\n';exit(0);}
        if(a[i][j]<k){
            l[i][j]=l[i-1][j]+1;
            s[i][j]=1;
        }
    }
    for(int i=1;i<=n;++i){
        for(int j=1;j<=n;++j)
            sum[i][j]=a[i][j]+sum[i][j-1];
        for(int j=1;j<=n;++j)
            sum[i][j]+=sum[i-1][j];
    }
    int res=0;
    int x=0,y=0,w=0,c=0,pd=0;
    for(int i=1;i<=n;++i){
        for(int i=1;i<=n+1;++i)wi[i]=0;
        head=0,tail=0;
        for(int j=1;j<=n+1;++j){
            int p=l[i][j],zc=0;
            while(p<q[tail]){
                zc+=wi[tail];
                x=i,y=j-1;w=i-q[tail--]+1,c=j-zc;
                if(ask(w,c,x,y)>=k){
                    pd=1;
                    res=ask(w,c,x,y);break;
                }
            }
            if(pd)break;
            q[++tail]=p;wi[tail]=zc+1;
        }
        if(pd)break;
    }
    if(res<k){std::cout<<"NIE\n";exit(0);}
    if(res>=k&&res<=k*2){std::cout<<c<<' '<<w<<' '<<y<<' '<<x<<'\n';exit(0);}
    for(int i=w;i<=x;++i){
        if(res>=k&&res<=k*2){std::cout<<c<<' '<<i<<' '<<y<<' '<<x<<'\n';exit(0);}
        int zc=ask(i,c,i,y);
        if(zc>=k){
            for(int j=c;j<=y;++j){
                zc=ask(i,j,i,y);
                if(zc>=k&&zc<=2*k){std::cout<<j<<' '<<i<<' '<<y<<' '<<i<<'\n';exit(0);}
            }
        }
        res-=zc;
    }   

}

T3 数组(CF1114F Please, another Queries on Array? )

欧拉函数的求法 \(\phi(n)=n\prod_{i=1}^{cnt}\frac{p_i-1}{p_i}\),\(p\) 表示 \(n\) 的质因数。
知道这个之后就是线段树板题了,维护区间乘积和区间质因数状态即可。
注意到 \(300\) 之内只有 \(63\) 个质因数,long long 直接就能存下。

点击查看代码
#include<bits/stdc++.h>
#define int long long
typedef long long ll;
typedef unsigned long long ull;
inline int read(){char ch=getchar();int x=0,f=1;for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);return x*f;}
const int N=4e5+10,mod=1e9+7;
int n,a[N],as[N],p[N],tot,ny[N];
struct TREE{int ans,s,tag1,tag2,l,r;}t[N<<2];
bool vis[N];
inline void init(){
    int MAXN=305;
    for(int i=2;i<=MAXN;++i){
        if(!vis[i])p[++tot]=i,as[i]|=(1ll<<tot-1);
        for(int j=1;j<=tot&&p[j]*i<=MAXN;++j){
            int x=p[j]*i;
            vis[x]=1;as[x]=as[p[j]]|as[i];
            if(i%p[j]==0)break;
        }
    }
}
inline int qpow(int a,int b){
    int res=1;
    for(;b;b>>=1,a=a*a%mod)if(b&1)res=res*a%mod;
    return res;
}
inline void update(int p){t[p].ans=t[p<<1].ans*t[p<<1|1].ans%mod;t[p].s=t[p<<1].s|t[p<<1|1].s;}
inline void pushdown(int p){
        int ls=p<<1,rs=p<<1|1;
        int zc=qpow(t[p].tag1,t[ls].r-t[ls].l+1);
        t[ls].ans=t[ls].ans*zc%mod;
        t[ls].s=t[ls].s|t[p].tag2;
        t[ls].tag1=t[ls].tag1*t[p].tag1%mod;
        t[ls].tag2=t[ls].tag2|t[p].tag2;
        zc=qpow(t[p].tag1,t[rs].r-t[rs].l+1);
        t[rs].ans=t[rs].ans*zc%mod;
        t[rs].s=t[rs].s|t[p].tag2;
        t[rs].tag1=t[rs].tag1*t[p].tag1%mod;
        t[rs].tag2=t[rs].tag2|t[p].tag2;
        t[p].tag1=1;t[p].tag2=0;
}
inline void build(int p,int l,int r){
    t[p].l=l,t[p].r=r;t[p].tag1=1;
    if(l==r){t[p]={a[l],as[a[l]],1,0,l,r};return ;}
    int mid=l+r>>1;
    build(p<<1,l,mid);build(p<<1|1,mid+1,r);
    update(p);
}
inline void add(int p,int l,int r,int x,int y,int v){
    if(l>=x&&r<=y){
        int zc=qpow(v,r-l+1);
        t[p].tag1=t[p].tag1*v%mod;
        t[p].tag2=t[p].tag2|as[v];
        t[p].ans=t[p].ans*zc%mod;
        t[p].s|=as[v];
        return;
    }
    pushdown(p);
    int mid=l+r>>1;
    if(x<=mid)add(p<<1,l,mid,x,y,v);
    if(y>mid)add(p<<1|1,mid+1,r,x,y,v);
    update(p);
}
inline std::pair<int,int> ask(int p,int l,int r,int x,int y){
    if(l>=x&&r<=y){return {t[p].ans,t[p].s};}
    pushdown(p);
    int mid=l+r>>1,_1=1,_2=0;
    if(x<=mid){auto it=ask(p<<1,l,mid,x,y);_1=_1*it.first%mod;_2|=it.second;}
    if(y>mid){auto it=ask(p<<1|1,mid+1,r,x,y);_1=_1*it.first%mod,_2|=it.second;}
    return {_1,_2};
}
signed main(){
    // freopen("array.in","r",stdin);freopen("array.out","w",stdout);
    std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);
    n=read();int q=read();
    init();
    for(int i=1;i<=n;++i)a[i]=read();build(1,1,n);
    for(int i=1;i<=tot;++i)ny[i]=qpow(p[i],mod-2);
    for(int i=1;i<=q;++i){
        char opt[10];
        scanf("%s",opt);
        int l=read(),r=read();
        if(opt[0]=='M')add(1,1,n,l,r,read());
        else{
            auto it=ask(1,1,n,l,r);
            int ans=it.first,s=it.second;
            for(int j=1;j<=63;++j){
                if(s&(1ll<<j-1)){
                    ans=ans*(p[j]-1)%mod*ny[j]%mod;
                }
            }
            std::cout<<ans<<'\n';
        }
    }
}

T4 树(P3591 [POI2015] ODW)

考虑根号分治,处理出每个点的 \(k\le\sqrt n\) 级祖先和前缀值。
对于 \(c\le \sqrt n\),找出 LCA 后直接树上差分即可,时间复杂度在于求 LCA。
对于 \(c>\sqrt n\),直接每次跳 \(\sqrt n\) 步来凑 \(c\) 即可,时间复杂度 \(O(\sqrt n)\)。
整个算法的时间复杂度为 \(O(n\sqrt n)\),和长链剖分一样优秀。

点击查看代码
#include<bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
inline int read(){char ch=getchar();int x=0,f=1;for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);return x*f;}
const int N=5e4+10,M=250;
int n,w[N],b[N],c[N],st[N][20],dep[N],dis[N][M],f[N][M],dfn[N];
std::vector<int> e[N];
inline void dfs(int u,int fa){
    st[u][0]=fa;f[u][1]=fa;
    if(u!=1)dis[u][1]=dis[fa][1]+w[u];
    for(int i=2;i*i<=n&&i<=dep[u];++i){
        f[u][i]=f[f[u][i-1]][1];
        dis[u][i]=dis[f[u][i]][i]+w[u];
    }
    for(int i=1;i<=std::__lg(dep[u]);++i)st[u][i]=st[st[u][i-1]][i-1];
    for(int v:e[u])if(v!=fa)dep[v]=dep[u]+1,dfs(v,u);
}
inline int LCA(int u,int v){
    if(dep[u]<dep[v])std::swap(u,v);
    while(dep[u]>dep[v])u=st[u][std::__lg(dep[u]-dep[v])];
    if(v==u)return v;
    for(int i=std::__lg(dep[u]);i>=0;--i)
        if(st[u][i]!=st[v][i])u=st[u][i],v=st[v][i];
    return st[u][0];
}
inline void ask1(int u,int v,int k){
    int lca=LCA(u,v),res=0;
    if((dep[u]-dep[lca])%k==0)res-=w[lca];
    int zc=dep[u]-dep[lca];
    zc-=zc%k;
    int x=u;
    if(zc){
        for(int i=std::__lg(zc);i>=0;--i)
            if(zc>=(1<<i))zc-=1<<i,x=st[x][i];
    }
    res+=dis[u][k]-dis[x][k]+w[x];
    u=v;
    zc=dep[u]-dep[lca];
    zc-=zc%k;
    x=u;
    if(zc){
        for(int i=std::__lg(zc);i>=0;--i)
            if(zc>=(1<<i))zc-=1<<i,x=st[x][i];
    }
    res+=dis[u][k]-dis[x][k]+w[x];
    std::cout<<res<<'\n';
}
inline void ask2(int u,int v,int k){
    int lca=LCA(u,v),res=w[u]+w[v];
    int zc=(dep[u]-dep[lca])/k;
    if((dep[u]-dep[lca])%k==0)res-=w[lca];
    for(int i=1;i<=zc;++i){
        int wk=k,x=sqrt(n);
        while(wk>=x){
            u=f[u][x];
            wk-=x;            
        }
        if(wk)u=f[u][wk];
        res+=w[u];
    }
    u=v;
    zc=(dep[u]-dep[lca])/k;
    for(int i=1;i<=zc;++i){
        int wk=k,x=sqrt(n);
        while(wk>=x){
            u=f[u][x];
            wk-=x;            
        }
        if(wk)u=f[u][wk];
        res+=w[u];
    }
    std::cout<<res<<'\n';
}
signed main(){
    // freopen("tree.in","r",stdin);freopen("tree.out","w",stdout);
    std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);
    n=read();
    for(int i=1;i<=n;++i)w[i]=read();
    for(int i=1;i<n;++i){int u=read(),v=read();e[u].push_back(v);e[v].push_back(u);}
    for(int i=1;i<=n;++i)b[i]=read();
    for(int i=1;i<n;++i)c[i]=read();
    dfs(1,0);
    for(int i=1;i<n;++i){
        if(c[i]*c[i]>=n){ask2(b[i],b[i+1],c[i]);}
        else ask1(b[i],b[i+1],c[i]);
    }
    return 0;
}

赛时相当于保龄了,明明 T3 和 T4 一眼就切了,赛时代码小改一下就 A 了,赛时没分,感觉自己总是不能把想到的很迅速地实现,期望得分和实际差得太多,这场期望 350pts,除了 T2 想了想没啥思路,别的都挺一眼的。
赛时策略也唐氏了,先冲的 T4,赛后发现空间炸了,一分没有,改下块长就过了。
T3 没打很不好,T1没判断好也傻逼。
还是得多打比赛,

标签:ch,int,res,long,zc,&&,CSP,模拟
From: https://www.cnblogs.com/Ishar-zdl/p/18299443

相关文章

  • 暑假模拟赛总结
    csp-j模拟赛2A公式求值加入前缀和思想的高精度加法。B最长的Y我永远喜欢IOI赛制。考场写了两份代码,调了两个小时,结果到最后10分钟发现第一个代码能够subtask1,第二个能过subtask2,于是结合起来喜提\(60\)分。我们先找到每一个\(Y\)块,然后循环找到左右两边离他......
  • 7.12 模拟赛总结
    这是暑假的第一个模拟赛,和新高一的一起打的T1T2T3T4tot50pts45pts100pts0pts195tps总的来说不是很满意,最近的状态有点低迷,但考虑到刚刚结束文化课还是情有可原,一切都会好起来的!T1[USACO09DEC]CowTollPathsG题意:给定\(n,n\le300\)个点,\(m,m\le1e4......
  • CSP提高组模拟1
    T1很明显的最短路floyed算法,但是这个最大的点权却不是很好维护,但我们可以想到枚举最大的点权其实就可以相当于枚举floyed中的k,那么这时我们要对k进行一个排序操作,使得我们每次枚举的中转点k为枚举经过路径的点权最大的点从而达到同时走最短路并维护点权最大值。点击查看代码#......
  • 信息学奥赛初赛天天练-45-CSP-J2020阅读程序1-字符数组默认值、字符串长度、字符数组
    PDF文档公众号回复关键字:202407122020CSP-J阅读程序11阅读程序(程序输入不超过数组或字符串定义的范围;判断题正确填√,错误填×。除特殊说明外,判断题1.5分,选择题3分,共计40分)01#include<cstdlib>02#include<iostream>03usingnamespacestd;0405ch......
  • CSP提高组模拟1
    我的微軟輸入法莫名其妙變成繁體了,你們有什麽頭緒嗎狀態題目20TimeExceededA最短路25TimeExceededB方格取数0TimeExceededC数组70TimeExceededD树A.最短路我赛时想了想,会不会DIJ不是很对,因为这个题在打的时候觉得,在跑最短路的时候......
  • 2024.7.12 模拟赛
    A容易观察到每个“\(1\)”相当于是独立的,那么其位置越靠后越优,则对于\(i=1\ton-1\),每次都为\(a_i\)选择一个最大的满足\(i+2^t\leqn\)的\(t\)全部进行操作最优。使用__builtin_clz函数做到\(O(n)\),暴力算\(t\)做到\(O(n\logV)\)。B要想求出每个前缀的答案,就......
  • PGSQL快速生成模拟数据
    背景有时候,我们为了测试数据库的性能,通常需要快速构建测试数据,PgSql提供了快速构建数据的工具,方便我们能够快捷的构建模拟数据。生成函数顺序生成生成SQL--生成一批顺序值SELECTidFROMGENERATE_SERIES(1,10)t(id);结果id1234......
  • HumanoidBench——模拟仿人机器人算法有未来
    概述论文地址:https://arxiv.org/pdf/2403.10506仿人机器人具有类似人类的外形,有望在各种环境和任务中为人类提供支持。然而,昂贵且易碎的硬件是这项研究面临的挑战。因此,本研究开发了使用先进模拟技术的HumanoidBench。该基准利用仿人机器人评估不同算法的性能,其中包括各......
  • 操作系统课程设计-模拟文件管理系统java实现
    模拟文件管理系统学校的期末课程设计,进行一个简单的分享,不足之处请各位大佬指正。一、主要内容综合运用操作系统理论知识和编程知识设计实现一个可视化操作的文件管理模拟系统,该系统包含的基本信息:创建用户、登录用户、创建文件、删除文件、打开文件、显示文件、关闭文......
  • YC312A [ 20240702 CQYC省选模拟赛 T1 ] 第一题(diyiti)
    题意给定一个长度为\(n\)的可重集,以及正整数\(k\)。设一个子集的价值为子集中最大值减去最小值,你需要将这个可重集划分为\(k\)个子集,使得价值之和最小,子集需要满足不重。\(n,k\le100\)。Sol思考一下发现如果不记录每个子集的信息是不好做的。考虑将所有子集的大小记......