2025“钉耙编程”中国大学生算法设计春季联赛补题
1001 数列计数
难点
给定两个长度为\(n\)的正整数序列\(a_i\)与\(l_i\),对于每个\(a_i\),求有多少个大小在\([0,l_i]\)内的\(b_i\)满足\(a_i\&b_i=b_i\)
思路
对于\(a_i\)和\(l_i\)在二进制形式下的每一位,可以发现如下规律:
\(a_i\)二进制形式下的第\(j\)位 | \(l_i\)二进制形式下的第\(j\)位 | 第\(j\)位对答案的贡献\(f(i,a_i,l_i)\) |
---|---|---|
0 | 0 | 0 |
1 | 0 | 0 |
0 | 1 | 2的\(a_i\)在\([0,j-1]\)二进制位下1的个数次幂 |
1 | 1 | 2的\(a_i\)在\([0,j-1]\)二进制位下1的个数次幂+\(f(i-1,a_i-2^j,l_i-2^j)\) |
也就是可以递归来求解,有些细节需要特别处理一下,具体可以看代码
代码实现
vector<int>suf(33);
int mod=998244353;
int f(int i,int x,int y){if(i==0){if(x==1&&y==1) return 2;else return 1;}if(y>>i&1){if(x>>i&1){return (1ll<<suf[i-1])+f(i-1,x-(1ll<<i),y-(1ll<<i));}return (1ll<<suf[i-1]);} if(x>>i&1) return f(i-1,x-(1ll<<i),y);return f(i-1,x,y);
}
void solve(){int n;cin>>n;vector<int>a(n+1),l(n+1);rep(i,1,n) cin>>a[i];rep(i,1,n) cin>>l[i];int ans=1;rep(i,1,n){int tmp=0;if(a[i]<=l[i]){tmp=(1ll<<__builtin_popcount(a[i]));}else{suf[0]=a[i]&1;rep(j,1,30){suf[j]=suf[j-1]+(a[i]>>j&1);} tmp=f(30,a[i],l[i]);}ans=(ans*tmp)%mod;}cout<<ans<<"\n";
}