这次比赛我应该是100分的,但是只有20,就因为堆的down操作打错了。。。gg。
T1:【NOIP2017提高A组冲刺11.2】字典序
最水的一题了,而且也是唯一会做的一题。
就是拓扑排序,再用一个堆优化一下。就好了。
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int last[100010],next[100010],tov[100010];
int n,m,tot;
int f[100010];
int ans[100010];
int num[100010];
void insert(int x,int y)
{
tov[++tot]=y;
next[tot]=last[x];
last[x]=tot;
}
void up(int x)
{
while((x>>1)>0&&f[x]<f[x>>1])
{
swap(f[x],f[x>>1]);
x=x>>1;
}
}
void down(int x)
{
int k;
while(((x<<1)<=tot&&f[x]>f[x<<1])||((x<<1)+1<=tot&&f[x]>f[(x<<1)+1]))
{
k=x<<1;
if(k+1<=tot&&f[k+1]<f[k])++k;
swap(f[x],f[k]);
x=k;
}
}
int main()
{
freopen("dictionary.in","r",stdin);
freopen("dictionary.out","w",stdout);
scanf("%d%d",&n,&m);
int i,x,y,j;
for (i=1;i<=m;++i)
{
scanf("%d%d",&x,&y);
insert(x,y);
++num[y];
}
tot=0;
for (i=1;i<=n;++i)
if(num[i]==0)
{
f[++tot]=i;
up(tot);
}
while(tot)
{
x=f[1];
ans[++ans[0]]=x;f[1]=f[tot--];down(1);
i=last[x];
while(i)
{
y=tov[i];
--num[y];
if(!num[y])
{
f[++tot]=y;
up(tot);
}
i=next[i];
}
}
if (ans[0]<n) printf("-1");
else
for (i=1;i<=ans[0];++i) printf("%d ",ans[i]);
printf("\n");
}
T2:【NOIP2017提高A组冲刺11.2】救赎
先用树形dp做出每一个节点为根的期望值。
然后可以递归每个点为根时的期望。这样它的父亲节点就会成为它的儿子。
然后推一推就对了。
#include<cstdio>
#include<iostream>
using namespace std;
long long f[100010];
int last[200010],next[200010],tov[200010];
long long size[100010],son[100010];
long long n,sum,tot,p=998244353;
long long ans[100010];
void insert(int x,int y)
{
tov[++tot]=y;
next[tot]=last[x];
last[x]=tot;
}
long long ksm(long long x,long long y)
{
long long k=1,z=x;
while (y>0)
{
if (y&1==1) k=(k*z)%p;
y=y/2;
z=(z*z)%p;
}
return k;
}
long long moon(long long x,long long y){return ((x-1)*((y-1)*ksm(y,p-2)%p))%p;}
void dfs(long long x,int father)
{
size[x]=1;
for (long long i=last[x];i;i=next[i])
{
if(tov[i]!=father)
{
dfs(tov[i],x);
size[x]+=size[tov[i]];
son[x]++;
}
}
f[x]=moon(size[x],son[x])%p;
sum=(sum+f[x])%p;
}
void dfs_ans(long long x,long long sf,long long sa,long long father)
{
long long son_now,son_next;
if(x==1) son_now=son[x];
else son_now=son[x]+1;
ans[x]=(sum-sf-f[x]+moon(n,son_now)%p+sa+p*2)%p;
for (long long i=last[x];i;i=next[i])
{
if(tov[i]!=father)
{
if(x==1) son_next=son[x]-1;
else son_next=son[x];
dfs_ans(tov[i],(sf+f[x])%p,(sa+moon(n-size[tov[i]],son_next))%p,x);
}
}
}
int main()
{
freopen("redemption.in","r",stdin);
freopen("redemption.out","w",stdout);
scanf("%lld",&n);
long long i,x,y;
for (i=1;i<=n-1;++i)
{
scanf("%lld%lld",&x,&y);
insert(x,y);
insert(y,x);
}
dfs(1,0);
dfs_ans(1,0,0,0);
for (i=1;i<=n;++i)
printf("%lld\n",ans[i]);
}
T3: 【NOIP2017提高A组冲刺11.2】失格
这题我改的最久。
我们可以发现这是一道最小生成树,然后就会发现不能暴力连边,我们可以只连刚好大于这个点的每个倍数的点。
然后最小生成树的排序部分用筒排。
就过了,细节注意。
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
struct cdy{int x,y,z;};
struct cdy2{int x,y;};
int n,tot;
cdy2 p[100010],p1[100010];
int ans,len;
int a[100010];
int f[100010];
cdy edge[32000001];
int num[10000001];
int q[32000001],q1[32000001];
int sum[10000001],chen[10000001];
bool cmp2(cdy2 a,cdy2 b){return a.x<b.x;}
int find(int x)
{
if(f[x]==x)return x;
f[x]=find(f[x]);
return f[x];
}
int main()
{
freopen("autosadism.in","r",stdin);
freopen("autosadism.out","w",stdout);
scanf("%d",&n);
int i,j,ma=0;
tot=0;
for (i=1;i<=n;++i)
{
scanf("%d",&p[i].x);
ma=max(ma,p[i].x);
p[i].y=i;
}
sort(p+1,p+1+n,cmp2);
for (i=1;i<=n;++i)
{
if(p[i].x==p[i-1].x)
{
edge[++tot].x=p[i].y;
edge[tot].y=p[i-1].y;
edge[tot].z=0;
}
else
{
p1[++len].x=p[i].x;
p1[len].y=p[i].y;
}
}
int s,l,r,mid,x;
l=2;
for (i=1;i<=ma;++i)
{
if(i<=p1[l-1].x) chen[i]=l-1;
else
{
chen[i]=l;
++l;
}
}
for (i=1;i<=len-1;++i)
{
edge[++tot].x=p1[i].y;
edge[tot].y=p1[i+1].y;
edge[tot].z=p1[i+1].x%p1[i].x;
x=i+1;
for (j=2;j<=ma/p1[i].x;++j)
{
s=j*p1[i].x;
if(chen[s]!=x)
{
l=chen[s];
edge[++tot].x=p1[i].y;
edge[tot].y=p1[l].y;
edge[tot].z=p1[l].x%p1[i].x;
x=l;
}
}
}
ma=0;
for (i=1;i<=tot;++i)
{
++num[edge[i].z];
ma=max(ma,edge[i].z);
}
for (i=0;i<=ma;++i)
sum[i]=sum[i-1]+num[i];
for (i=1;i<=tot;++i)
{
q[++q[0]]=sum[edge[i].z];
q1[q[q[0]]]=i;
--sum[edge[i].z];
}
for (i=1;i<=n;++i) f[i]=i;
int xx,yy,ans,k;
ans=k=0;
for (i=1;i<=q[0];++i)
{
xx=find(edge[q1[i]].x);
yy=find(edge[q1[i]].y);
if(xx!=yy)
{
++k;
f[xx]=yy;
ans+=edge[q1[i]].z;
}
if(k==n-1)break;
}
printf("%d\n",ans);
}