ABC351 简要题解
A,B,C都是语法题跳了。
D
让你构造 300 个数,输入 ,使得这 300 个数选不超过 3 个加起来可以表示出 所有的数
一开始想二进制拆分,然后发现总会超。
然后神说可以十进制,恍然大明白。就是 最大 ,然后分成 组,每组 个数,正好能装下。就是第一组是 ,第二组是 ,第三组是 ,正好所有数都能表示出来,297 个数。
E
DP简单题。就是设 到第 种操作,这种选不选的最小代价,然后对于第一种操作选不选分别讨论一下就行。
F
分别是 dfs 树和 bfs 树。
对于第一种,如果存在横叉边,那一定会在 dfs 的过程中先走那条边,导致不存在横叉边,只有树边和返祖边。
对于第二种,如果存在返祖边,那么它正常应该在它祖先被扩展时一起扩展进去,所以一定不存在返祖边。
G
计算几何——半平面交
跳了
Ex
假设一开始的 个数是 。然后提起一层时的 个数为 ,再往上提一层为 ,再下一层为 。
然后发现全是二项式系数。
也就是到第 层时,第 个数为 。
这样复杂度还是会寄。观察到 比较小,所以考虑从这里下手。
因为一个数会覆盖一段,一段里又可以分成 段,每段里的 都相同,只有二项式系数不同。所以如果能快速地求二项式系数的前缀和,问题就解决了。
对于组合数的前缀和:,考虑先用卢卡斯定理,推个式子,然后用类似整除分块的东西拆一下,然后就能递归算了。左转这道题(懒得打式子了)[SHOI2015]超能粒子炮·改
但是你发现,对于 个数, 段都求,再算个前缀和是 的,过不了。
但是发现,每次移动一位, 段的贡献只有每段的分界点会有变化。其他的和上一次是一样的。 所以每次只需要维护 个变化量,所以优化成了 的。
但是还是不行,还是需要优化。
我们发现复杂度卡在求组合数上。我们考虑这东西能不能被优化掉。我们发现 Lucas 的过程就是相当于 进制的拆分。所以我们考虑把进制里高位和低位分别预处理出来,然后到时直接查表就行。
具体来讲就是 中 是固定的,所以把 的所有的结果全预处理出来, 也全预处理出来。然后如果查 就直接查 .
这样我们就把它优化成了 。
注意卡常
我好像写麻烦了,但是神的代码好什么看不懂。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll c[20][20],f[20][20];
ll n;int m,K;
int mod=7;
int a[203],cc[203];int posl[203],posr[203],Lx[203],Rx[203];
ll Lucas(ll n,ll K)
{
if(!K) return 1;
if(n<K) return 0;
if(n==K) return 1;
return (c[n%mod][K%mod]*Lucas(n/mod,K/mod))%mod;
}
ll f1[200030],f2[200030];
ll lucas(ll n,ll k)
{
return (f1[k%117649]*f2[k/117649])%mod;
}
ll F(ll n,ll K)
{
if(K<0) return 0;
if(!K||!n) return 1;
if(n<mod&&K<mod) return f[n][K];
return ((f[n%mod][mod-1]*F(n/mod,K/mod-1))%mod+(f[n%mod][K%mod]*Lucas(n/mod,K/mod))%mod)%mod;
}
int main()
{
// freopen("p.in","r",stdin);
// freopen("p.out","w",stdout);
c[0][0]=1;
for(int i=1;i<=7;i++)
{
c[i][0]=1;
for(int j=1;j<=i;j++)
c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
}
for(int i=0;i<=7;i++)
{
f[i][0]=1;
for(int j=1;j<=7;j++)
f[i][j]=(f[i][j-1]+c[i][j])%mod;
}
scanf("%lld%d%d",&n,&m,&K);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&a[i],&cc[i]);
}
if(n==K)
{
for(int i=1;i<=m;i++)
{
while(cc[i]--)
printf("%d ",a[i]);
}
return 0;
}
ll B1=0;ll lst=0; ll kk=0;
memset(posl,-1,sizeof(posl)); memset(posr,-1,sizeof(posr));
for(int i=1;i<=m;i++)
{
Lx[i]=kk,Rx[i]=kk+cc[i]-1;
if(kk>n-K+1) {kk=cc[i]+kk;continue;}
ll cur=F(n-K,min(kk+cc[i]-1,n-K));
B1=(B1+(cur-lst)*a[i])%mod; B1=(B1+mod)%mod;
posr[i]=min(kk+cc[i]-1,n-K); posl[i]=kk;
kk=kk+cc[i]; lst=cur;
}
int mx=117649;
for(int i=0;i<=mx;i++) f1[i]=Lucas((n-K)%mx,i);
for(int i=0;i<=mx;i++) f2[i]=Lucas((n-K)/mx,i);
int st=1;
printf("%lld ",B1);
// for(int i=1;i<=m;i++) fprintf(stderr,"posl[%d]=%d,posr[%d]=%d\n",i,posl[i],i,posr[i]);
int LL=0,RR=n-K;
for(int j=2;j<=K;j++)
{
ll ret=B1;
LL++; RR++;
for(int i=st;i<=m;i++)
{
int lx=posl[i],rx=posr[i];
if(lx==0)
{
if(rx==0){ret-=a[i]; posl[i]=posr[i]=-2;st=i+1;continue;}
else if(rx==n-K&&Rx[i]>=RR) break;
else if(rx==n-K&&Rx[i]==RR-1) {ret-=(f1[rx%117649]*f2[rx/117649])*a[i],posr[i]=rx-1;ret=(ret+mod)%mod;continue;}
else {ret-=(f1[rx%117649]*f2[rx/117649])*a[i],posr[i]=rx-1;ret=(ret+mod)%mod;continue;}
}
else if(lx>0)
{
if(rx>0&&(rx!=n-K||(rx-lx+1==cc[i])))
{
lx--;ret=(ret+f1[lx%117649]*f2[lx/117649]*a[i])%mod; posl[i]=lx;
ret-=f1[rx%117649]*f2[rx/117649]*a[i],ret=(ret+mod)%mod, posr[i]=rx-1;
}
else
posl[i]=lx-1,ret=(ret+f1[posl[i]%117649]*f2[posl[i]/117649]*a[i])%mod;
}
else if(lx==-2) continue;
else if(lx==-1)
{
if(posr[i-1]==n-K-1) ret=(ret+a[i])%mod,posl[i]=posr[i]=n-K;
break;
}
}
printf("%lld ",(ret+7)%7);
//fprintf(stderr,"%d %.3lf\n",j,1.0*clock()/CLOCKS_PER_SEC);
// for(int i=1;i<=m;i++) fprintf(stderr,"posl[%d]=%d,posr[%d]=%d\n",i,posl[i],i,posr[i]);
B1=ret;
}
}
本文作者:cc0000
本文链接:https://www.cnblogs.com/cc0000/p/16945775.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步