首页 > 其他分享 >NOIP 模拟9

NOIP 模拟9

时间:2023-11-02 15:25:26浏览次数:34  
标签:cnt NOIP int sum long include 模拟 MOD

100+100+100+80,T4 \(O(n\log n)\) 没卡过,赛后没改 \(O(n)\),加了 WX 超级快读。

为啥放了套简单题,题目出处好像是 22csp 7连 day1。

A.上海

对 \(k\) 质因数分解,\(k=\sum\limits p_i^{c_i}\),使 \(n\) 最小且 \(k\mid n^2\) 就是使 \(n=\sum\limits p_i^{\lceil\frac{c_i}{2}\rceil}\)。

当 \(n=k\) 时没有解,其实这种情况下说明所有质因数的次数都是 \(1\);否则就有解的,时间复杂度 \(O(\sqrt k)\)。

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<math.h>
using namespace std;
long long k,tmp,ans=1;
int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    cin.tie(0),cout.tie(0);
    ios::sync_with_stdio(0);
    cin>>k;tmp=k;
    for(int i=2;i<=sqrtl(tmp);++i)
    {
        int cnt=0;
        for(;!(k%i);k/=i) ++cnt;
        for(int j=1;j<=(cnt+1)/2;++j) ans*=i;
    }
    ans*=k;cout<<(ans==tmp?-1:ans)<<'\n';return 0;
}

B.华二

发现只有 \(6\) 拥有 \(2\) 个质因数,其它都只有一个。

所以先考虑只有 \(2\) 的倍数或 \(3\) 的倍数的数能组成多少种排列,发现任何数无法跨过 \(6\),同时其它的\(2\) 的倍数或 \(3\) 的倍数的数都相当于是已经排好顺序的。所以按 \(6\) 分割而开,每一段的排列数是 \(\dbinom{2\text{的倍数的个数}}{总个数}\),总排列数求积即可。

剩下就只有 \(1,5,7\),同理每个数都相当于独立排好顺序的,直接记录出现个数,然后就是合并几个排列了。时间复杂度 \(O(n)\)。

#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN=1e5+10,MOD=998244353;
int n,a[MAXN],cnt1,cnt2,cnt3,cnt4,cnt5;
long long ans=1,P[MAXN],inv[MAXN];
inline long long ksm(long long a,int b)
{
    long long ans=1;
    while(b)
    {
        if(b&1) ans=ans*a%MOD;
        a=a*a%MOD,b>>=1;
    }
    return ans;
}
inline long long C(int n,int m)
{
    if(n<m) return 0;
    return P[n]*inv[m]%MOD*inv[n-m]%MOD;
}
int main()
{
    freopen("b.in","r",stdin);
    freopen("b.out","w",stdout);
    cin.tie(0),cout.tie(0);
    ios::sync_with_stdio(0);
    cin>>n;
    P[0]=1;for(register int i=1;i<=n;++i) P[i]=P[i-1]*i%MOD;
    inv[n]=ksm(P[n],MOD-2);
    for(register int i=n-1;i>=0;--i) inv[i]=inv[i+1]*(i+1)%MOD;
    for(int i=1;i<=n;++i)
    {
        cin>>a[i];
        if(a[i]==2||a[i]==4||a[i]==8) cnt1++;
        if(a[i]==3||a[i]==9) cnt2++;
        if(a[i]==1) cnt3++;
        if(a[i]==5) cnt4++;
        if(a[i]==7) cnt5++;
        if(a[i]==6||i==n) ans=ans*C(cnt1+cnt2,cnt1)%MOD,cnt1=cnt2=0;
    }
    ans=ans*C(n-cnt4-cnt5,cnt3)%MOD*C(n-cnt5,cnt4)%MOD*C(n,cnt5)%MOD;cout<<ans<<'\n';return 0;
}

C.高爸

发现单峰,所以二分。发现不好维护,所以开个动态开点值域线段树,维护一下区间中下标和与个数和,用来求函数值。然后把二分改成线段树上二分,每次比较 \(F(mid)\) 与 \(F(mid+1)\) 的大小,决定递归到哪个儿子,时间复杂度 \(O(n\log n)\)。

#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int INF=1e9;
int n,a,b,cnt=1;long long suma,sumb,cnta,cntb;
struct tree{long long sum;int cnt,ls,rs;}t[30000000];
inline int LS(int p){if(!t[p].ls) t[p].ls=++cnt;return t[p].ls;}
inline int RS(int p){if(!t[p].rs) t[p].rs=++cnt;return t[p].rs;}
inline void push_up(int p)
{
    t[p].sum=t[t[p].ls].sum+t[t[p].rs].sum;
    t[p].cnt=t[t[p].ls].cnt+t[t[p].rs].cnt;
    return ;
}
inline void change(int l,int r,int p,int x)
{
    if(l==r){t[p].sum+=x,t[p].cnt++;return ;}
    int mid=(l+r)>>1;
    if(x<=mid) change(l,mid,LS(p),x);
    else change(mid+1,r,RS(p),x);
    push_up(p);return ;
}
inline long long F(int x){return (cnta*x-suma)*a+(sumb-cntb*x)*b;}
inline void query(int l,int r,int p)
{
    if(l==r)
    {
        suma+=t[p].sum,cnta+=t[p].cnt;
        cout<<F(l)<<'\n';return ;
    }
    int mid=(l+r)>>1;
    suma+=t[t[p].ls].sum,sumb+=t[t[p].rs].sum;
    cnta+=t[t[p].ls].cnt,cntb+=t[t[p].rs].cnt;
    if(F(mid)<F(mid+1))
    {
        suma-=t[t[p].ls].sum,cnta-=t[t[p].ls].cnt;
        query(l,mid,LS(p));
    }
    else
    {
        sumb-=t[t[p].rs].sum,cntb-=t[t[p].rs].cnt;
        query(mid+1,r,RS(p));
    }
    return ;
}
int main()
{
    freopen("c.in","r",stdin);
    freopen("c.out","w",stdout);
    cin.tie(0),cout.tie(0);
    ios::sync_with_stdio(0);
    cin>>n>>a>>b;
    for(int i=1,x;i<=n;++i)
    {
        cin>>x;change(0,INF,1,x);
        suma=sumb=cnta=cntb=0;query(0,INF,1);
    }
    return 0;
}

D.金牌

将一条路径 \(l\to r\),拆成 \(l\to x,x\to y,y\to r\),设每段长度 \(a,b,c\),所以\(\sum 2^{a+b+c}=\sum (2^a\times 2^b\times 2^c)=2^b\times \sum 2^a\times\sum 2^c\)。

所以求出每个点本身及其子树中的点到它的权值和 \(d_x\) 与所有点到它的权值和 \(g_x\)。

对于一次询问 \(x,y\),记 \(L=\operatorname{lca}(x,y)\),钦定 \(dep_x\leq dep_y\)。

  • 若 \(x\not = L\),则答案为 \(d_x\times d_y\times 2^{\operatorname{dist}(x,y)}\)。
  • 若 \(x= L\),则记 \(y\) 的 \(dep_x-dep_y-1\) 级祖先为 \(k\),答案为 \((g_x-2d_k)\times d_y\times 2^{\operatorname{dist}(x,y)}\)。

先一遍 dfs 求出 \(d_x=1+\sum\limits_{y\in son(x)} 2d_y\)。

再一遍 dfs 求出 \(g_x=d_x+2(g_{fa_x}-2d_x)\)。

剩下就是求 \(\operatorname{lca}\) 与 \(k\) 级祖先,用树剖卡常,\(O(n\log n)\),建议用超级快读优化高达 \(10^6\) 的输入输出,写的清真一点可过。

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<time.h>
#include<string.h>
using namespace std;
const int MAXN=1e6+10,MOD=998244353;
int n,q,root,to[MAXN<<1],nxt[MAXN<<1],head[MAXN],cnt;
int dep[MAXN],fa[MAXN],siz[MAXN],hson[MAXN],top[MAXN];
long long d[MAXN],g[MAXN],P[MAXN];
namespace Octane {
    //省略 WX 超级快读
} using namespace Octane;
inline void add(int x,int y)
{
    to[++cnt]=y,nxt[cnt]=head[x];
    head[x]=cnt;return ;
}
void dfs(int x)
{
    d[x]=siz[x]=1,dep[x]=dep[fa[x]]+1;
    for(int i=head[x];i;i=nxt[i])
    {
        int y=to[i];if(y==fa[x]) continue;
        fa[y]=x,dfs(y),d[x]+=(d[y]<<1),siz[x]+=siz[y];
        if(siz[y]>siz[hson[x]]) hson[x]=y;
    }
    d[x]%=MOD;return ;
}
void dfs_2(int x)
{
    g[x]=d[x]+(fa[x]?((g[fa[x]]-(d[x]<<1))<<1):0),g[x]%=MOD;
    for(int i=head[x];i;i=nxt[i])
    {
        int y=to[i];if(y==fa[x]) continue;
        top[y]=(y==hson[x])?top[x]:y,dfs_2(y);
    }
    return ;
}
inline int lca(int x,int y)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    return x;
}
inline int get_fa(int x,int y)
{
    while(dep[top[x]]>dep[y]+1) x=fa[top[x]];
    return (top[x]==top[y])?hson[y]:top[x];
}
int main()
{
    freopen("d.in","r",stdin);
    freopen("d.out","w",stdout);
    cin>>n;srand(time(0)),root=rand()%n+1;
    for(int i=1,x,y;i<n;++i) cin>>x>>y,add(x,y),add(y,x);
    dfs(root),top[root]=root,dfs_2(root);
    P[0]=1;for(int i=1;i<=n;++i) P[i]=(P[i-1]<<1)%MOD;
    cin>>q;
    while(q--)
    {
        int x,y,L;cin>>x>>y;L=lca(x,y);
        if(dep[x]>dep[y]) swap(x,y);
        if(x!=L) cout<<d[x]*d[y]%MOD*P[dep[x]+dep[y]-(dep[L]<<1)]%MOD<<'\n';
        else
        {
            int k=get_fa(y,x);
            cout<<(d[y]*(g[x]-(d[k]<<1))%MOD*P[dep[x]+dep[y]-(dep[L]<<1)]%MOD+MOD)%MOD<<'\n';
        }
    }
    return 0;
}

标签:cnt,NOIP,int,sum,long,include,模拟,MOD
From: https://www.cnblogs.com/int-R/p/NOIP9.html

相关文章

  • STL之红黑树的模拟实现(万字长文详解)
    STL之红黑树的模拟实现红黑树的概念红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。通过对任何一条从根到叶子的路径上各个结点着色方式的限制,==红黑树确保没有一条路径会比其他路径长出俩倍==,因而是==接近平衡==的。==意思就是最长路......
  • C4D2024+Redshift 3.5.20 三维计算机动画、建模、模拟和渲染软件_中文/英文WIN版
     Cinema4D是什么?Cinema4D2024下载:hereitis.cn/soft/c4dCinema4D是一款专业的3D建模、动画、模拟和渲染解决方案软件。它的快速、强大、灵活和稳定的工具集使设计、运动图形、VFX、AR/MR/VR、游戏开发和所有类型的可视化专业人员获得更容易和高效的3D工作流程。无......
  • 模拟五
    收官之战!!!模拟赛五补题报告日期:\(2023\)—\(10\)—\(6\)学号:\(S11390\)一、总分:\(T1\)重复判断:\(100\)分\(T2\)歪果仁学乘法:\(100\)分\(T3\)去重求和:\(40\)分\(T4\)点集操作:\(0\)分共:\(240\)分二、比赛过程在第一题中,我在考试中通过遍历字符串的方式,一个一个......
  • 模拟实现.net中的Task机制:探索异步编程的奥秘
    .net中使用Task可以方便地编写异步程序,为了更好地理解Task及其调度机制,接下来模拟Task的实现,目的是搞清楚:Task是什么Task是如何被调度的基本的Task模拟实现从最基本的Task用法开始Task.Run(Actionaction)这个命令的作用是将action作为一项任务提交给调度器,调度器会安排......
  • 2023NOIP A层联测22 差后队列
    2023NOIPA层联测22差后队列挺有意思的期望题,题解做法应该是DP,但是我又双叒写出奇怪的做法……思路除去最大值外的元素个数的倒数就是这一轮取到某个数的概率,而最大值是特殊的情况,在被替代之前或作为最后一个数被弹出之前,不参与计算。对于操作0的输出和操作1的输出分开......
  • 10.31 NOIP模拟测试
    10.31NOIP模拟测试赛时先看题,T1有一点思路,T2是我不擅长的期望计数,但看起来还是可以试一试,T3数据范围看起来是NP,想了一下搜索但没有一下想出来,T4一眼大数据结构,最后做。T1想了一下前缀和,去上了个厕所,中途想出后缀和和前缀和比较,回去写看打样例发现不仅要比较相邻的,还要比......
  • NOIP 模拟8(NOIP A层联测22)
    \(100+100+40+0\),T3卡时没卡对挂了\(20\)。后来发现赛时T3是时间复杂度和正确性都是对的,只是常数大导致我以为它跑不出来。A.集合给定一个序列,求有多少个子区间满足这个区间的数的集合的所有值域连续段长度都不超过\(k\)。答案满足单调性,双指针统计答案,权值线段树维护最......
  • NOIP2003 传染病控制 深搜/剪枝
    思路题目大意是:把一棵树按深度分层,每一层断掉一条边,是剩下的节点数最小。其实,我们可以将问题转换为断掉的节点数最多。首先,贪心不可行,很容易被卡。因为数据只有300,直接搜索就行。搜索时一层一层搜,枚举断掉哪条边,并标记后代。#include<bits/stdc++.h>usingnamespacestd;......
  • NOIP2023模拟8联测29 C. 蛋糕
    NOIP2023模拟8联测29C.蛋糕目录NOIP2023模拟8联测29C.蛋糕题目大意思路code题目大意你现在得到了一个二维蛋糕,它从左到右可以分成\(n\)列,每列高为\(a_i\)。对于每一列,又可以从下到上分为\(a_i\)块,并且最上面一块权值为\(1\),从上到下权值依次加。每一列的最上面的......
  • 软件模拟实现IEEE-754单精度浮点数运算
    软件模拟实现IEEE-754单精度浮点数运算本文首发于吾爱破解论坛https://www.52pojie.cn/thread-1830228-1-1.html大多数CPU都有硬件的浮点单元(FPU),但是有一些MCU使用的内核(比如Cortex-M3)没有FPU,或者一些内核只支持单精度,同时大部分CPU都不支持高精度128位的浮点数,如果需要使用这......