2017.12.09NOIP提高组模拟赛A组

Posted _patrick

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2017.12.09NOIP提高组模拟赛A组相关的知识,希望对你有一定的参考价值。

2017.12.09【NOIP提高组】模拟赛A组

T1 3489. 【NOIP2013模拟联考11】数列的GCD(gcd)
T2 3500.【NOIP2013模拟联考15】物语(monogatari)
T3 3501.【NOIP2013模拟联考15】消息传递(news)

吐槽:这次的题好像有点水啊,但最简单的第二题都给打挂啦!!(数组开小了)

T1

本套题中最难的题。考虑dp
设f[i]是b[1],b[2]...b[N]的最大公约数的数目,g[i]是b[1],b[2]...b[N]的公约数的数目。
则显然有\(g[i]=\sum_{d|i}f[d]\)
g[i]十分好求。

设l[i]为{a[N]}中满足 i|a[j] (1<=j<=N)的数目

\[g[d]={l[d] \choose n-k}\lfloor\frac{m}{d}\rfloor^{n-l[d]}(\lfloor\frac{m}{d}\rfloor-1)^{l[d]-n+k}\]

Code

#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define rep(i,x) for(int i=head[x];i;i=next[i])
#define mem(a,x) memset(a,x,sizeof(a))
typedef long long LL;
typedef double DB;
using namespace std;
inline int read() {
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9') f=(ch=='-')?-1:f,ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+(ch-'0'),ch=getchar();return f*x;
}
const int n=300010,mo=1e9+7;
int a[n],cnt[n],ji[n];
LL fac[n],ans[n];
LL qpow(LL a,int b) {
    a=a%mo;
    LL ans=1;
    for(;b;a=(a*a)%mo,b>>=1) if(b&1) ans=(ans*a)%mo;
    return ans;
}
LL C(int m,int n) {return fac[n]*qpow(fac[m],mo-2)%mo*qpow(fac[n-m],mo-2)%mo;}
int main() {
    int n=read(),m=read(),k=read();
    k=n-k;
    fo(i,1,n) a[i]=read(),ji[a[i]]++;
    fd(i,m,1) for(int j=i;j<=m;j+=i) cnt[i]=cnt[i]+ji[j];
    fac[0]=1;
    fo(i,1,n) fac[i]=((LL)fac[i-1]*i)%mo;
    fd(i,m,1) {
        if(cnt[i]<k) ans[i]=0;
        else {
            ans[i]=C(k,cnt[i])*qpow(m/i-1,cnt[i]-k)%mo*qpow(m/i,n-cnt[i])%mo;
            fo(j,2,m/i) ans[i]=(ans[i]+mo-ans[i*j])%mo;
        }
    }
    fo(i,1,m) printf("%lld ",ans[i]);
    return 0;
}

T2

最简单的题。

只用考虑经不经过这个点即可,经过可分为两种情况:
技术分享图片
将就着看一下吧,正反做一遍dij就行了。

Code

#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
#define pr pair<LL, int>
#define mp make_pair
#define x first
#define y second
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define rep(i,x) for(int i=head[x];i;i=g[i].next)
#define mem(a,x) memset(a,x,sizeof(a))
typedef long long LL;
typedef double DB;
using namespace std;
inline int read() {
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9') f=(ch=='-')?-1:f,ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+(ch-'0'),ch=getchar();return f*x;
}
const LL INF=0x7ffffffffffff;
const int N=5e5+50,M=5e5+50;
struct Edge {int x,next;LL dis;} g[M*2] ;
int n,m,k,begin,end,tx,ty,ww;
LL G[N],F[N];
int head[N],w,vis[N];
priority_queue<pr>q;
void add(int x,int y,LL dis) {g[++w].x=y,g[w].next=head[x],g[w].dis=dis,head[x]=w;}
void dij(int x) {
    int tmp;
    LL now;
    fo(i,1,n) F[i]=INF;
    F[x]=0,q.push(mp(0,x));
    while(!q.empty()) {
        x=q.top().y;
        LL now=q.top().x;q.pop();
        if(-now>F[x]) continue;
        now=-now;
        rep(i,x) if(F[tmp=g[i].x]>F[x]+g[i].dis) F[tmp]=F[x]+g[i].dis,q.push(mp(-F[tmp],tmp));
    }
}
int main() {
//  freopen("2.in","r",stdin);
    freopen("monogatari.in","r",stdin),freopen("monogatari.out","w",stdout);
    n=read(),m=read(),k=read();
    fo(i,1,m-1) {tx=read(),ty=read(),scanf("%lld",&ww),add(tx,ty,ww),add(ty,tx,ww);}
    scanf("%d%d",&begin,&end);
    dij(1);
    memcpy(G,F,sizeof(G));
    dij(n);
    fo(i,1,k) {
        scanf("%lld",&ww);
        LL tmp=min(G[n],min(G[begin]+F[end],G[end]+F[begin])+ww);
        if(tmp==INF) printf("+Inf\n") ;
        else printf("%lld\n",tmp) ;
    }
}

T3

考虑树形dp,明显要旋根,记录每个点儿子的前缀和后缀最大值。
随便搞一下就行了。(很简单,相出dp就行了)

Code

#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define rep(i,x) for(int i=head[x];i;i=next[i])
#define mem(a,x) memset(a,x,sizeof(a))
typedef long long LL;
typedef double DB;
using namespace std;
inline int read() {
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9') f=(ch=='-')?-1:f,ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+(ch-'0'),ch=getchar();return f*x;
}
const int mn=401000;
int n,tt=1,fa[mn],head[mn],next[mn*2],to[mn*2];
int f[mn],g[mn],sum[mn],ans[mn],u[mn],q[mn],cnt=0;
int pre[mn],sa[mn],tot;
void add(int i,int j) {next[++tot]=head[i],head[i]=tot,to[tot]=j;}
bool cmp(int i,int j) {return sum[i]<sum[j];}
void solve() {
    int a=1,b=1;
    q[1]=1;
    while(a<=b) {
        int now=q[a++];
        rep(p,now) if(to[p]!=fa[now]) q[++b]=to[p];
    }
    fd(i,n,1) {
        int now=q[i],tt=0;
        rep(p,now) if(to[p]!=fa[now]) u[++tt]=f[to[p]];
        sort(u+1,u+1+tt);
        fo(j,1,tt) f[now]=max(f[now],u[j]+tt-j+1);
    }
    ans[1]=f[1];
    fo(i,1,n) {
        int now=q[i],tt=0;
        rep(p,now) if(to[p]!=fa[now]) u[++tt]=to[p],sum[to[p]]=f[to[p]];
        if(now!=1) u[++tt]=fa[now],sum[fa[now]]=g[now];
        sort(u+1,u+1+tt,cmp);
        pre[0]=sa[tt+1]=0;
        fo(j,1,tt) ans[now]=max(ans[now],sum[u[j]]+tt-j+1);
        fo(j,1,tt) pre[j]=max(pre[j-1],sum[u[j]]+tt-j);
        fd(j,tt,1) sa[j]=max(sa[j+1],sum[u[j]]+tt-j+1);
        fo(j,1,tt) if(u[j]!=fa[now]) g[u[j]]=max(pre[j-1],sa[j+1]);
    }
}
int main() {
    freopen("news.in","r",stdin),freopen("news.out","w",stdout);
    n=read();
    fo(i,2,n) fa[i]=read(),add(fa[i],i),add(i,fa[i]);
    int tmp=1<<30;
    solve();
    fo(i,1,n) tmp=min(tmp,ans[i]);
    printf("%d\n",tmp+1);
    fo(i,1,n) if(ans[i]==tmp) printf("%d ",i);
    bool first=1;
    return 0;
}

以上是关于2017.12.09NOIP提高组模拟赛A组的主要内容,如果未能解决你的问题,请参考以下文章

2017.11.25NOIP提高组模拟赛A组

2017.12.02NOIP提高组模拟赛A组

NOIP提高组模拟赛13

P1065 [NOIP2006 提高组] 作业调度方案(模拟)

Jzoj4742NOIP2016提高A组模拟9.2快速幂单峰

NOIP2016提高A组模拟10.15总结