ICode9

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

NOIP提高组模拟赛7

2022-01-23 08:01:10  阅读:185  来源: 互联网

标签:NOIP int 提高 long num ans include 模拟 mod


A. 工业题 / a

带取模的运算,除以一个数一定要乘逆元!!!!!!!!!!!!!!!!!!

不同位置的值对最终答案的贡献是互不影响的,分开考虑每个值的贡献

考虑对于位于\((x,y)\)的值对\((n,m)\)的贡献,无论从哪个路径走过去,一定是原数\(*a^{m-x}*b^{n-y}\),而对答案贡献多少次即为\((x,y)->(n,m)\)不同的路径数,这个显然是个组合数,用l表示需要走几步,r表示需要向右(或下)走几步,那么方案数为\(C_l^r\),为了方便计算,我们从方案数唯一的开始算,这样每次通过\(C_l^r\),求\(C_{l+1}^{r+1}\)只需要\(*(l+1)/(r+1)\)记得用逆元

#include<cstdio>
#include<cstring>
using namespace std;
const int mod=998244353;
long long a,b;
long long x[300005],y[300005];
int n,m;
long long qp(long long x,long long y){
    long long ans=1;
    while(y){
        if(y&1)ans=(ans*x)%mod;
        x=(x*x)%mod;
        y>>=1;
    }
    return ans;
}
int main(){
    scanf("%d%d%lld%lld",&n,&m,&a,&b);
    for(int i=1;i<=n;++i)scanf("%lld",&x[i]);
    for(int i=1;i<=m;++i)scanf("%lld",&y[i]);
    for(int i=1;i<=n;++i)x[i]%=mod;
    for(int i=1;i<=m;++i)y[i]%=mod;
    a%=mod;b%=mod;
    long long nm=qp(a,m),nn=qp(b,n);
    long long c=1,l=m-1,r=0,ans=0,num=nm;
    for(int i=n;i>=1;--i){
        ans=(ans+((x[i]*c)%mod*num)%mod)%mod;
        ++l,++r;c=(c*(l%mod)%mod*qp(r,mod-2))%mod;num=(num*b)%mod;
    }
    c=1,l=n-1,r=0,num=nn;
    for(int i=m;i>=1;--i){
        ans=(ans+((y[i]*c)%mod*num)%mod)%mod;
        ++l,++r;c=((c*l)%mod*qp(r,mod-2))%mod;num=(num*a)%mod;
    }
    printf("%lld\n",ans);
    return 0;
}

B. 卡常题 / b

n个点,2n条边,还是连通图,那么图中有且只有一个环,是一棵基环树

如果将一个y点和其黑白边看成一条边,可以省去y点,将黑白边当作点权加到x点上,这样仍然得到基环树

其实问题已经可以转化为在基环树上任意相邻两点必须有一个激活,激活费用为点权的最小花费

任意一条边所连的两点必然有一个被激活,我们考虑断掉环上的一边,转化为普通的树形DP,两次DP分别激活断开的两点,取个min即可

#include<cstdio>
#include<cstring>
using namespace std;
int min(int x,int y){return x<y?x:y;}
const int maxn=1000005;
struct edge{
    int to,net;
}e[maxn<<1|1];
int d[maxn],head[maxn],tot=1;
void add(int u,int v){
    e[++tot].net=head[u];
    head[u]=tot;
    e[tot].to=v;
}
bool vis[maxn];
int del,root1,root2;
bool dfs(int x,int fx){
    vis[x]=1;
    for(int i=head[x];i;i=e[i].net){
        int v=e[i].to;
        if(v==fx)continue;
        if(vis[v]){del=i;root1=x;root2=v;return 1;}
        if(dfs(v,x))return 1;
    }
    return 0;
}
int f[maxn][2];
void work(int x,int fx){
    for(int i=head[x];i;i=e[i].net){
        int v=e[i].to;
        if(v==fx||i==del||i==(del^1))continue;
        work(v,x);
        f[x][0]+=f[v][1];
        f[x][1]+=min(f[v][0],f[v][1]);
    }
    f[x][1]+=d[x];
}
int n;
int main(){
    int a,b;
    scanf("%d%d%d",&n,&a,&b);
    for(int i=1;i<=n;++i){
        int u,v;scanf("%d%d",&u,&v);
        d[u]+=a;d[v]+=b;add(u,v);add(v,u);
    }
    bool p=dfs(1,0);
    work(root1,0);
    int ans=f[root1][1];
    memset(f,0,sizeof(f));
    work(root2,0);
    ans=min(ans,f[root2][1]);
    printf("%d\n",ans);
    return 0;
}

C. 玄学题 / c

考场脑抽系列

发现是完全平方数才会有影响(奇数个因子),

枚举n只需求对已知\(i(i\in[1,n])[1,m]\)中有多少数与之相乘为完全平方数

将i写成\(q*p_1^2\)的形式,其中q不含平方因子,与i相乘为完全平方数的数一定能写成\(q*p_2^2\)

问题转化为求小于等于\(m/q\)的完全平方数有几个,开方即可,不难想到

\(sqrt(m/q)\)即为所求

#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=10000005;
long long a[maxn];
long long n,m;
void work(){
    for(long long i=1;i*i<=n;++i)
     for(long long j=1;j*i*i<=n;++j)
       a[i*i*j]=j;
    long long ans=0;
    for(long long i=1;i<=n;++i)
     if(((long long)sqrt(m/a[i]))&1)--ans;
     else ++ans;
    printf("%lld\n",ans);
}
int main(){
    scanf("%lld%lld",&n,&m);
    work();
    return 0;
}

标签:NOIP,int,提高,long,num,ans,include,模拟,mod
来源: https://www.cnblogs.com/Chencgy/p/15835672.html

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

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

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

ICode9版权所有