Jee, You See?
https://codeforces.com/contest/1670/problem/F
理论
l < = a 1 + a 2 + . . . + a n < = r l<=a_1+a_2+...+a_n<=r l<=a1+a2+...+an<=r
a 1 ⨁ a 2 ⨁ . . . ⨁ a n = z a_1\bigoplus a_2\bigoplus...\bigoplus a_n=z a1⨁a2⨁...⨁an=z
sum=a1+a2+…+an
那么只需要把sum<=r 的情况-sum<=l-1的情况就是答案数
那么只用计算sum<=x时a1a2…^an=z的方案数
z所在的位数为1时,一定有奇数个数的数当前位为1,反之则有偶数个
dp[i] [j]为到第i位时,剩下多少个1可以添加到当前位
转移时,会发现j会变的非常大,要考虑简化状态,找找有没有相同的或者对结果没有影响的状态
k
位
前
的
数
之
和
最
大
为
n
∗
(
2
0
+
2
1
+
.
.
.
+
2
k
−
1
)
=
n
∗
(
2
k
−
1
)
<
n
∗
(
2
k
)
,
所
以
对
于
当
前
位
,
把
剩
下
可
以
为
1
的
数
量
>
=
n
全
做
n
处
理
,
对
后
面
的
结
果
无
影
响
。
k位前的数之和最大为n*(2^0+2^1+...+2^k-1)=n*(2^k-1)<n*(2^k),所以对于当前位,把剩下可以为1的数量>=n全做n处理,对后面的结果无影响。
k位前的数之和最大为n∗(20+21+...+2k−1)=n∗(2k−1)<n∗(2k),所以对于当前位,把剩下可以为1的数量>=n全做n处理,对后面的结果无影响。
状 态 转 移 时 , 第 k + 1 位 剩 下 的 可 以 为 1 的 数 量 为 i 时 , 那 么 k 位 为 1 的 数 量 最 多 为 2 ∗ i + ( ( x < < k ) & 1 ) 状态转移时,第k+1位剩下的可以为1的数量为i时,那么k位为1的数量最多为2*i+( ( x < < k ) \& 1 ) 状态转移时,第k+1位剩下的可以为1的数量为i时,那么k位为1的数量最多为2∗i+((x<<k)&1)
得 到 递 推 式 : d p [ k ] [ m i n ( 2 ∗ i + ( ( x > > k ) & 1 ) − j , n ) ] + = d p [ k + 1 ] [ i ] ∗ C [ n ] [ j ] / / j 为 枚 举 的 当 前 位 放 置 的 数 量 得到递推式:dp[k] [min(2*i+((x>>k)\&1)-j,n)]+=dp[k+1] [i] *C[n] [j]//j为枚举的当前位放置的数量 得到递推式:dp[k][min(2∗i+((x>>k)&1)−j,n)]+=dp[k+1][i]∗C[n][j]//j为枚举的当前位放置的数量
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define F(i, a, b) for(int i = a; i <= (b); ++i)
#define F2(i, a, b) for(int i = a; i < (b); ++i)
#define dF(i, a, b) for(int i = a; i >= (b); --i)
#define pb push_back
#define pf push_front
#define fi first
#define sc second
#define inf 0x3f3f3f3f
#define mod 998244353
#define infll 0x3f3f3f3f3f3f3f3f
#define mkp make_pair
const int N=1e3+7;
const int P=1e9+7;
int n;
ll C[N][N];
ll l,r,z;
void init(){
C[0][0]=1;
F(i,1,n)
F(j,0,i)
{
if(!j) C[i][j]=1;
else C[i][j]=(C[i-1][j-1]+C[i-1][j])%P;
}
}
ll cal(ll x){
ll dp[64][N]={0};
dp[60][0]=1;
for(int k=59;k>=0;k--){
for(int i=0;i<=n;i++)//枚举前一位还能放置多少个1,大于n的都当作n,因为大于n对后续的影响都和n一样,都能让后面位全部填满
{
if(!dp[k+1][i]) continue;
int now=2*i+((x>>k)&1);//当前位最多能放置的数量
for(int j=(z>>k)&1;j<=min(n,now);j+=2){
dp[k][min(now-j,n)]+=dp[k+1][i]*C[n][j]%P;
dp[k][min(now-j,n)]%=P;
}
}
}
ll ans=0;
F(i,0,n) ans+=dp[0][i];
return ans%P;
}
void solve(){
scanf("%d%lld%lld%lld",&n,&l,&r,&z);
init();
printf("%lld\n",(cal(r)-cal(l-1)+P)%P);
}
int main(){
//freopen("C:\\Users\\86155\\Desktop\\1.in","r",stdin);
//freopen("C:\\Users\\86155\\Desktop\\1.out","w",stdout);
int t=1;
while(t--){
solve();
}
return 0;
}