Jeanny
寂兮,寥兮,独立不改,周行而不殆

T2 开平方

要证明“$x$ 能表示为两个平方数之差当且仅当 $x$ 是奇数或4的倍数”,需从以下两方面分析:


1. 充分性(满足条件的数一定能表示为平方差)
奇数:  
  设 $x = 2k + 1$($k$ 为整数)。取 $y = k + 1$,$z = k$,则:  
  
  $y^2 - z^2 = (k + 1)^2 - k^2 = 2k + 1 = x.$
    
  因此,所有奇数均可表示为平方差。

 4的倍数:  
  设 $x = 4k$($k$ 为整数)。取 $y = k + 1$,$z = k - 1$,则:
  $y^2 - z^2 = (k + 1)^2 - (k - 1)^2 = 4k = x.$
  因此,所有4的倍数均可表示为平方差。


2. 必要性(能表示为平方差的数必为奇数或4的倍数)
平方差公式为 $x = (y - z)(y + z)$,令 $a = y - z$,$b = y + z$,则 $a$ 和 $b$ 需满足:  
1. $a$ 和 $b$ 同奇偶性:  
   因为 $a + b = 2y$ 必须为偶数,所以 $a$ 和 $b$ 同为奇数或同为偶数。  
2. $x = a \cdot b$:  
   若 $a$ 和 $b$ 均为奇数,则 $x$ = 奇数 $\times$ 奇数 = 奇数。  
   若 $a$ 和 $b$ 均为偶数,设 $a = 2m$,$b = 2n$,则 $x = 4mn$,即 $x$ 为4的倍数。  

综上,若 $x$ 可表示为平方差,则 $x$ 必为奇数或4的倍数。

---

结论

充要条件 :$x$ 能表示为两个平方数之差当且仅当 $x$ 是奇数或4的倍数。 

 

code
#include <bits/stdc++.h>
using namespace std;

signed main() {
    int L, R;
    cin >> L >> R;
    // 计算奇数个数
    int odd = (R + 1) / 2 - L / 2;
    // 计算4的倍数个数
    int mul4 = R / 4 - (L - 1) / 4;
    cout << odd + mul4;
    return 0;
}

 

T4 异或

考虑20%的特殊数据,发现可以把贡献拆分,我们可以考虑将问题分解到每一位上,分别计算每一位对总和的贡献。
贡献拆分:联想- “开灯,还是开灯”这道题

100%的数据:
对于第k位(从最低位开始,k=0,1,2,...),如果x(x<=n)的第k位是1,y(y<=m)的第k位是0,其余可以随意,对答案的贡献是个组合数。

对于不是每一位可以随意选择0或者1的数字,可以转而考虑周期性。
000000[0]0
000000[0]1
000000[1]0
000000[1]1
000001[0]0
000001[0]1
000001[1]0
000001[1]1
000010[0]0
000010[0]1
000010[1]0
...
可以观察得到,对于第k位,先是0,后是1,周期大小是2^(k+1).
第k位的周期是2^(k+1),即每2^(k+1)个数,第k位会经历2^k个0和2^k个1。
具体来说,对于第k位:
在完整的周期中,0和1的个数都是2^k。
对于不完整的部分,可以计算余下的数中有多少个0和1。

ans = 第k位【 x(x<=n)中的1 】* 【 y(y<=m)中的0】 +  【x(x<=n)中的0】 *【 y(y<=m)】中的1       * (1<<k) 

```
for (int i = 0; i <= 60; ++i) {//周期规律 000...111
    LL x = 1LL << (i + 1LL);//周期的大小
    LL y = x>>1;            //周期大小的一半
    LL c = (n + 1LL)/x;    //有多少个完整的周期
    LL p = (n + 1LL)%x;    //不完整的部分
    ua[i] = (c * y % M + max(p - y, 0LL) % M) % M;//完整的周期个数 * 周期的一半 + 不完整的部分 - 周期的一半
    ub[i] = (n - ua[i]) % M;
}
```

查看代码
 #include<bitsstdc++.h>
#define LL long long
using namespace std;
const int N = 67;
const LL M = 998244353;
int T;
LL n, m, ua[N], ub[N], va[N], vb[N];
int main() {
    scanf("%d", &T);
    while (T--) {
        scanf("%lld%lld", &n, &m);
        for (int i = 0; i <= 60; ++i) {//周期规律 000...111
            LL x = 1LL << (i + 1LL);//周期的大小
            LL y = x>>1;            //周期大小的一半
            LL c = (n + 1LL)/x;    //有多少个完整的周期
            LL p = (n + 1LL)%x;    //不完整的部分
            ua[i] = (c * y % M + max(p - y, 0LL) % M) % M;//完整的周期个数 * 周期的一半 + 不完整的部分 - 周期的一半
            ub[i] = (n - ua[i]) % M;
        }
        for (int i = 0; i <= 60; ++i) {
            LL x = 1LL << (i + 1LL);//周期的大小
            LL y = x>>1;            //周期大小的一半
            LL c = (m + 1LL)/x;    //有多少个完整的周期
            LL p = (m + 1LL)%x;    //不完整的部分
            va[i] = (c * y % M + max(p - y, 0LL) % M) % M;//完整的周期个数 * 周期的一半 + 不完整的部分 - 周期的一半
            vb[i] = (m - va[i]) % M;
        }
        LL ans = 0;
        for (int i = 0; i <= 60; ++i)
            (ans += (ua[i] * vb[i] % M + ub[i] * va[i] % M) % M * ((1LL << i) % M)) %= M;
        printf("%lld\n", ans);
    }
    return 0;
}
posted on 2025-05-02 16:28  Jeanny  阅读(30)  评论(0)    收藏  举报