4 条题解

  • 5
    @ 2026-9-16 15:41:49

    The Solution of string

    problem
    外网

    part 1, 二进制被 33 整除转化

    我们知道,十进制 33 的整除性是 各个数位相加的和是 3 的倍数,原理是因为 10k≡1(mod3)10^k \equiv 1 \pmod{3},所以

    $$num=a_k \times 10^k + a_{k-1} \times 10^{k-1} + \dots + a_0 \times 10^0 \equiv a_k + a_{k-1} + \dots + a_0 \pmod{3}$$

    二进制呢,我们可以列出 22 的幂次除以 33 的余数表

    幂次 00 11 22 33 44 55 …\dots
    余数 11 22 11 22 11 22 …\dots

    当 kk 是奇数时,2k≡2(mod3)2^k \equiv 2 \pmod{3};
    当 kk 是偶数时,2k≡1(mod3)2^k \equiv 1 \pmod{3};

    所以: 对于奇数位,对余数的贡献是 22; 对于偶数位,对余数的贡献是 11.

    进一步,我们就能推出:

    Codd≡Ceven(mod3)C_{odd} \equiv C_{even} \pmod{3}

    part 2,贪心

    对于最大值,肯定是越是填 11,越好,反之同理。那么问题就在与我们填了 11 或 00 之后可不可能填出 33 的倍数,如果可以就填,否则就填另一个。
    那么怎么判定呢,就用到了 part 11 的结论:

    Codd≡Ceven(mod3)C_{odd} \equiv C_{even} \pmod{3}

    part 3, check

    现在问题就在于,还剩 cnt1cnt_1 个 11,cnt0cnt_0 个 00,令 lft=cnt0+cnt12lft = \frac{cnt_0 + cnt_1}{2} ,奇数位和偶数位差为 dd,问此时可不可以。
    我们不妨假设奇数位数量与偶数位数量相同(如果不同就枚举当前位填什么),奇数位与偶数位的差为 00 或 11(如果是多 22,就可以改成少 11)。
    此时开始分类讨论:

    1. 奇数位和偶数位差为 00,cnt1cnt_1 为偶数,则一定可以,将 cnt1cnt_1 分成两份:奇偶各一份就行。
    2. 奇数位和偶数位差为 00,cnt1cnt_1 为奇数,则拿出三个放偶数,再平均分,判断偶数位够不够,此时 cnt1≥3cnt_1 \ge 3 且 cnt1−32+3≤lft\frac{cnt_1 - 3}{2} + 3 \le lft
    3. 奇数位和偶数位差为 11,cnt1cnt_1 为奇数,则拿出一个放偶数,再平均分,判断偶数位够不够,此时 cnt1≥1cnt_1 \ge 1 且 cnt1−12+1≤lft\frac{cnt_1 - 1}{2} + 1 \le lft
    4. 奇数位和偶数位差为 11,cnt1cnt_1 为偶数,则拿出两个放偶数,再平均分,判断偶数位够不够,此时 cnt1≥2cnt_1 \ge 2 且 cnt1−22+2≤lft\frac{cnt_1 - 2}{2} + 2 \le lft

    (代码中会将这些式子变形,应该能理解)

    part 4, 代码

    #include <bits/stdc++.h>
    using namespace std;
    
    int T, n, m;
    
    bool check(int one, int zero, int d) {
    	int lft = one + zero;
    	if (lft & 1) return one && check(one - 1, zero, (d + 2) % 3)
    		|| zero && check(one, zero - 1, d);
    	if (!d)
    		if (one & 1) return one >= 3 && ((one + 3) >> 1) <= (lft >> 1);
    		else return 1;
    	else if (one & 1) return one >= 1 && ((one + 1) >> 1) <= (lft >> 1);
    	else return one && (one >> 1) + 1 <= (lft >> 1);
    }
    
    int main() {
    	scanf("%d", &T);
    	while (T--) {
    		scanf("%d%d", &n, &m);
    		int one = n - 1, zero = m, d = (((n + m - 1) & 1) ? 1 : 2);
    		// max
    		if (!check(n - 1, m, 1)) { puts("-1\n-1"); continue; }
            printf("1");
    		for (int i = 2; i <= n + m; i++) {
    			int pos = n + m - i, nxt = ((pos & 1) ? (d + 1) % 3 : (d + 2) % 3);
    			if (one && check(one - 1, zero, nxt)) d = nxt, --one, printf("1");
    			else --zero, printf("0");
    		} puts("");
    		// min
            printf("1");
    		one = n - 1, zero = m, d = (((n + m - 1) & 1) ? 1 : 2);
    		for (int i = 2; i <= n + m; i++) {
    			int pos = n + m - i, nxt = ((pos & 1) ? (d + 1) % 3 : (d + 2) % 3);
    			if (zero && check(one, zero - 1, d)) --zero, printf("0");
    			else --one, d = nxt, printf("1");
    		} puts("");
    	}
    	return 0;
    }
    
    • 3
      @ 2026-9-16 19:04:01

      注意到2的偶数次幂模3为2,2的奇数次幂模3为1

      记在偶数位上的1的个数为x,奇数位上的1的个数为y

      若要使该数被3整除,需满足x=y或|x-y|=3 因为(1+2)%3=0,1x3%3=0,2x3%3=0; 故当n<=1时无解

      故当n%2=0时 字典序最大为1全放在前,0全方在后 字典序最小时,当m%2=时,第一位为1,0全放在前,1全方在后,当m%2!=0时,即最后连续的1的第一个的位数的奇偶与第以为的1相同时,使得|x-y|=2,故需要在最后的连续的1的第一个1后补0,使|x-y|=3

      当n%2==0时 则只能满足|x-y|=3,那么至少需要2个0来填位若没有则无解 字典序最大为1放在前,最后为0101,后添加0 字典序最小时考虑m的奇偶决定连续的1前为0101还是1010来保证|x-y|=3

      • -2
        @ 2026-9-16 17:19:41

        本文由GPT5.6撰写

        题解

        设二进制数为:

        b1b2⋯bn+mb_1b_2\cdots b_{n+m}

        因为

        2≡−1(mod3)2\equiv-1\pmod3

        所以这个数除以 3 的余数等于:

        b1−b2+b3−b4+⋯b_1-b_2+b_3-b_4+\cdots

        因此问题变成:

        让奇数位置的 1 数量 − 偶数位置的 1 数量是 3 的倍数。


        贪心

        我们从左往右确定每一位。

        • 求字典序最大:优先尝试放 1
        • 求字典序最小:优先尝试放 0
        • 第一位不能放 0

        假设当前尝试放了 x,那么剩下 r 个 1。

        设剩下有 O 个奇数位置、E 个偶数位置。

        如果剩余的 1 中有 y 个放在奇数位置,那么:

        r−yr-y

        个放在偶数位置,所以剩余贡献为:

        y−(r−y)=2y−ry-(r-y)=2y-r

        其中:

        max⁡(0,r−E)≤y≤min⁡(r,O)\max(0,r-E)\le y\le\min(r,O)

        我们只需要判断这个区间里是否存在一个 y,使最终的:

        奇数位置1数量−偶数位置1数量≡0(mod3)奇数位置1数量-偶数位置1数量\equiv0\pmod3

        因为只看模 3,所以实际上只需要检查最多 3 个 y。


        复杂度

        每个位置只尝试 0/1 两种情况,每次判断 O(1)。

        所以:

        O(n+m)\boxed{O(n+m)}

        空间复杂度:

        O(n+m)\boxed{O(n+m)}

        核心代码

        string work(int big){
            int N=n+m,one=n,sum=0;
            string s;
            for(int i=1;i<=N;i++){
                int O=(N+1)/2-(i&1),E=N/2-!(i&1);
                for(int x=big;x>=0;x--){
                    if((i==1&&x==0)||x>one) continue;
                    int r=one-x;
                    if(r>O+E) continue;
                    int l=max(0,r-E),R=min(r,O);
                    int t=(sum+(x?(i&1?1:-1):0))%3;
                    if(t<0)t+=3;
                    bool ok=0;
                    for(int y=l;y<=min(R,l+2);y++)
                        if((t+2*y-r)%3==0) ok=1;
                    if(ok){
                        s+=x+'0';
                        one-=x;
                        if(x) sum+=i&1?1:-1;
                        break;
                    }
                }
            }
            return one||sum%3?"-1":s;
        }
        

        一句话总结:利用 2≡-1 (mod 3) 把整串转成奇偶位置计数,然后从左到右贪心,每次判断剩余的 1 能否补出模 3 的合法方案。

        • @ 2026-9-16 17:25:53

          这个讲解的不清楚:

          补充一下

          内容为AI生成 对,这里确实应该从**“二进制数怎么判断能不能被 3 整除”**开始讲,不应该直接丢一句 2≡-1 (mod 3)。

          1. 先看普通的十进制

          比如十进制数:

          1234512345

          实际上就是:

          1×104+2×103+3×102+4×10+51\times10^4+2\times10^3+3\times10^2+4\times10+5

          判断它除以某个数的余数,本质上就是看这些幂次对这个数的余数。

          二进制也是完全一样的。


          2. 二进制数怎么表示?

          比如:

          101101
          

          它表示:

          $$1\times2^5+0\times2^4+1\times2^3+1\times2^2+0\times2^1+1\times2^0$$

          现在我们想判断它能不能被 3 整除。

          也就是想知道:

          25+23+22+12^5+2^3+2^2+1

          除以 3 的余数是多少。


          3. 看 2 的幂除以 3 的余数

          我们一个一个算:

          20=1≡1(mod3)2^0=1\equiv1\pmod3 21=2≡2(mod3)2^1=2\equiv2\pmod3 22=4≡1(mod3)2^2=4\equiv1\pmod3 23=8≡2(mod3)2^3=8\equiv2\pmod3 24=16≡1(mod3)2^4=16\equiv1\pmod3 25=32≡2(mod3)2^5=32\equiv2\pmod3

          你会发现规律:

          2^0  2^1  2^2  2^3  2^4  2^5
           1    2    1    2    1    2
          

          也就是说:

          • 偶数次幂 %3 = 1
          • 奇数次幂 %3 = 2

          而:

          2≡−1(mod3)2\equiv-1\pmod3

          其实就是说:

          2除以3余22除以3余2

          而 -1 除以 3 也可以理解成余 2。

          所以:

          2≡−1(mod3)2\equiv-1\pmod3

          并不是一个很神秘的东西,就是:

          2 和 -1 除以 3 的余数效果完全一样。


          4. 所以二进制数可以变成“正负交替”

          对于:

          101101
          

          原本是:

          $$1\times2^5+ 0\times2^4+ 1\times2^3+ 1\times2^2+ 0\times2+ 1$$

          因为:

          2^5 ≡ -1
          2^4 ≡  1
          2^3 ≡ -1
          2^2 ≡  1
          2^1 ≡ -1
          2^0 ≡  1
          

          所以变成:

          $$1\times(-1) +0\times1 +1\times(-1) +1\times1 +0\times(-1) +1\times1$$

          也就是:

          −1+0−1+1+0+1=0-1+0-1+1+0+1=0

          所以:

          101101101101

          可以被 3 整除。

          实际上:

          1011012=45101101_2=45

          确实:

          45÷3=1545\div3=15

          5. 最终得到一个非常好用的规律

          对于二进制:

          b1 b2 b3 b4 b5 b6 ...
          

          从左往右编号:

          位置: 1  2  3  4  5  6
                 +  -  +  -  +  -
          

          所以:

          奇数位置的1的数量−偶数位置的1的数量\boxed{ 奇数位置的1的数量 - 偶数位置的1的数量 }

          如果这个数是 3 的倍数,那么原二进制数就是 3 的倍数。

          例如:

          101101
          

          奇数位置:

          1 1 0 1
          

          有 3 个 1。

          偶数位置:

          0 1 0
          

          有 1 个 1。

          所以:

          3−1=23-1=2

          等等,这里要注意:上面按“从左往右位置”算时,正负号取决于总长度的奇偶性。

          为了避免这个坑,最稳妥的方法是从右往左看:

          101101
                ↓
          位置:6 5 4 3 2 1
                 + - + - + -
          

          因为最低位 2^0 一定是 +。

          所以实际上判断规则是:

          从右往左,奇数位的 1 加起来,偶数位的 1 减起来。

          对于 101101:

          从右往左:
          
          1 0 1 1 0 1
          + - + - + -
          

          得到:

          1−0+1−1+0−1=01-0+1-1+0-1=0

          所以能被 3 整除。


          这道题里为什么有用?

          因为我们构造的是 01 串,只需要知道:

          $$\boxed{\text{奇数位置的1数}-\text{偶数位置的1数}\equiv0\pmod3}$$

          就能判断整个二进制数是否能被 3 整除。

          于是原题就从:

          构造一个巨大的二进制数,使它能被 3 整除

          变成了:

          把 n 个 1 放到奇数、偶数位置,使两边数量之差是 3 的倍数。

          这就是后面贪心能够成立的关键。

      • -2
        @ 2026-9-16 17:15:05

        本文章由GPT5.6-Thinking撰写

        https://chatgpt.com/share/6aaa5efd-e9c0-83ec-8c7a-a89e286ac975

        思路

        设二进制串长度为 (L=n+m)。

        二进制数除以 (3) 时,因为

        $$2^0\equiv1,\quad 2^1\equiv-1,\quad 2^2\equiv1,\quad 2^3\equiv-1\pmod 3$$

        所以只需要看 从右往左奇偶位置上的 1 的数量。

        设其中有 (x) 个 1 位于偶数次幂的位置(也就是从右往左第 (1,3,5,\dots) 位),那么

        num≡x−(n−x)=2x−n(mod3)num\equiv x-(n-x)=2x-n\pmod3

        因此必须满足

        x≡2n(mod3)x\equiv 2n\pmod3

        于是问题变成:

        在固定的 n 个 1、m 个 0 下,让“奇数编号位置上的 1 的数量”模 3 等于 2n mod 3,然后贪心构造字典序最大/最小。

        贪心

        从左到右枚举每一位。

        构造最大串时优先放 1;构造最小串时优先放 0。

        尝试放完以后,只要判断剩下的位置能不能把条件补齐即可。

        假设还剩:

        • a 个 1
        • O 个“从右往左奇数位置”
        • E 个“从右往左偶数位置”
        • 当前已经用了 c 个奇数位置上的 1

        设剩下还要在奇数位置放 y 个 1。

        显然:

        max⁡(0,a−E)≤y≤min⁡(a,O)\max(0,a-E)\le y\le\min(a,O)

        同时需要

        c+y≡2n(mod3)c+y\equiv 2n\pmod3

        所以只要看这个区间里有没有对应模 3 的数即可,O(1) 判断。

        第一位强制放 1,避免前导 0。

        总复杂度为 O(n+m),空间 O(n+m)。

        C++14

        #include<bits/stdc++.h>
        using namespace std;
        
        #define int long long
        
        bool solve(int n,int m,bool mx,string &s){
            int L=n+m;
            int O=(L+1)/2,E=L/2;
            int target=2*n%3;
            int one=n,zero=m,c=0;
            s="";
        
            for(int i=1;i<=L;i++){
                bool odd=((L-i)%2==0);
                int first=mx?1:0,second=mx?0:1;
        
                int choose=-1;
                for(int t=0;t<2;t++){
                    int b=(t==0?first:second);
                    if(i==1&&b==0) continue;
                    if(b==1&&one==0) continue;
                    if(b==0&&zero==0) continue;
        
                    int no=O,ne=E,n1=one,nc=c;
                    if(odd) no--;
                    else ne--;
        
                    if(b==1){
                        n1--;
                        if(odd) nc++;
                    }
        
                    int lo=max(0LL,n1-ne);
                    int hi=min(n1,no);
                    int need=(target-nc+3)%3;
                    int x=lo+(need-lo%3+3)%3;
        
                    if(x<=hi){
                        choose=b;
                        break;
                    }
                }
        
                if(choose==-1) return false;
        
                s+=char('0'+choose);
                if(odd) O--;
                else E--;
        
                if(choose==1){
                    one--;
                    if(odd) c++;
                }else zero--;
            }
        
            return true;
        }
        
        signed main(){
            ios::sync_with_stdio(false);
            cin.tie(nullptr);
        
            int T;
            cin>>T;
        
            while(T--){
                int n,m;
                cin>>n>>m;
        
                string mx,mn;
                bool a=solve(n,m,1,mx);
                bool b=solve(n,m,0,mn);
        
                if(!a||!b){
                    cout<<-1<<"\n"<<-1<<"\n";
                }else{
                    cout<<mx<<"\n"<<mn<<"\n";
                }
            }
            return 0;
        }
        

        例如 n=5,m=5,程序会得到:

        1110101000
        1000101011
        

        和样例一致。

        • 1

        信息

        ID
        2741
        时间
        2000ms
        内存
        128MiB
        难度
        4
        标签
        (无)
        递交数
        25
        已通过
        11
        上传者