2017.12.09【NOIP提高组】模拟赛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;
}