code / 坠机:P17111 「FAOI-R13」addimnorsux II
fish_love_cat · · 题解
Warning:本篇题解没有代码实现,正确性存疑,请谨慎参考。推导思路与已有的公开题解均(事实上截止目前只有一篇)不相同,故先行发表。仅使用 AI 以及参照官方题解进行了正确性的核验。
如果有问题就叫我撤下来。
:::info[什么样的人生是失败的?(第十四弹)]
背景:all in T3 推式子。
开头:秒了 AB,剩下 3h 多,看了眼 D 打了个暴力发现怎么过不去 subtask 2 懒得思考了,钦定 t4 是困难题,发现榜上过了 5 个 C 于是决定 all in 推式子。
中间:推了三版式子假了两版,剩 30min 得到正确式子花了 10min 发现不会算,剩 15min 的时候发现好像这个式子可以转变成一个项数很少的 poly。
高潮:我不会拉插。
结尾:
结尾呢?不知道。或许这个折叠框是个墓碑吧。
R.I.P. :::
100 + 100 + 33 + 12 遗憾离场。
为什么会变成这样子呢?我问我自己。
详细揭秘组合意义天地灭。
首先
然后和减异或部分有经典位运算等式
所以问题就变成了一边左移一边与,交替进行,第一个是左移,最后一个也是左移,求所有划分球后得到的操作序列的结果。
最后一个左移先不看,容易发现这个东西每一步左移在前与在后,那么提前把左移的位给移好显然没有问题。
所以我们把这个玩意的对齐规则搞成一个平行四边形状物,前面高后面低,同样高的位置齐平。
因为数字二进制下长度顶天
此时的与就是要求这个平行四边形上的一个横线上全部都是
考虑构造一个双射,我们把这个线的部分往左边压平,压在开头数字上,然后要求第一个数字的一段连续位置一定得是
那么,我们直接对着这个东西做双指针,动态维护被强制要求的位置,把需要的球的数量从总量里扣去。
如果第一个数字禁止放球了那么是容易的,直接在其他数字里面做插板即可,但问题就出在这里。
因为我们只是强制要求了第一个数字上的一段是
低位的部分本质上是多了一个带上限的盒子,可以转单步容斥,用不带上界减去带下界的情况。带下界的话直接预先填充即可。
高位部分怎么处理?首先有可能不放球,那么我们不要这个盒子就是一个合法解。
否则至少会放
错的,你不能够侵蚀低位的地方。
所以高位限制的本质是放的球必须得是
不管上面的了,我们现在只需要解决,有
列出式子:
显然,直接算算不了。
但是根据定义我们知道,组合数
那么也就是说次数是
某个同学想到这里的时候,发现距离比赛结束还剩十五分钟。
组合数部分要用 lucas 定理优化,这个是简单的,略去不提。因为下指标非常小所以这部分可以看做
时间复杂度应该是
代码等我学了拉插来补。这里有一个完全按照这个式子写出来的 33 分暴力,没有 WA 所以式子应该没有问题。
:::info[暴力代码]
#include<bits/stdc++.h>
#define int long long
#define mod 599999
#define lowbit(x) (x&-x)
using namespace std;
int A[600005];
int inv[600005];
int qpow(int a,int b=mod-2){
int ans=1;
if(b==0)return 1;
while(b){
if(b&1)ans*=a,ans%=mod;
a*=a,b>>=1,a%=mod;
}
return ans;
}
int C(int n,int m){
if(m>n)return 0;
return (A[n]*inv[m]%mod*inv[n-m]%mod);
}
void init_of_C(int N){
A[0]=A[1]=1;
for(int i=2;i<=N;i++)
A[i]=A[i-1]*i%mod;
inv[N]=qpow(A[N]);
for(int i=N;i;i--)
inv[i-1]=inv[i]*i%mod;
}
int lucas(int n,int m){
if(n<m)return 0;
if(n==0)return 1;
return lucas(n/mod,m/mod)*C(n%mod,m%mod)%mod;
}
void solve(){
int n,s;
cin>>n>>s;
if(n>59){
cout<<"0\n";
return;
}
if(n==1){
cout<<s*2<<'\n';
return;
}
int x=0;
int flc=1;
for(int i=0;i<n;i++,flc<<=1)
x|=flc;
int ans=0;
int sj=0;
while(x<=s){
int sum=lucas(s-x+(n-1),s-x);
if(s-x>sj)
sum=((sum-lucas(s-x+(n-1)-sj-1,s-x-sj-1))%mod+mod)%mod;
int flc2=flc;
while(s-x>=flc2){
int qwq=s-x-flc2;
sum+=lucas(qwq+(n-1),qwq);sum%=mod;
if(qwq>sj)
sum=((sum-lucas(qwq+(n-1)-sj-1,qwq-sj-1))%mod+mod)%mod;
flc2+=flc;
}
ans=(ans+sum*(flc%mod)%mod)%mod;
x-=lowbit(x);
x|=flc;
flc<<=1;
sj<<=1;
sj|=1;
}
cout<<ans<<'\n';
}
signed main(){
init_of_C(mod-1);
int t;
cin>>t;
while(t--)solve();
return 0;
}
:::