1 条题解

  • 0
    @ 2026-4-25 22:50:14

    记有毒细菌为 11,无毒细菌为 00.


    考虑每次询问时如何通过每个时刻的细菌数量得到每个 00 连续段的长度.

    aia_i 为时刻 ii 剩余的 00 的数量,a1a_1 为初始 00 的数量.

    当询问串是全 11 或全 00 时,都会返回没有细菌死亡.

    其余情况,对于一个长为 ss00 连续段,若其在开头或末尾,则其会让 aia_imax(s+1i,0)\max(s+1-i,0),否则会让 aia_imax(s+22i,0)\max(s+2-2i,0).

    先假设所有 00 连续段都在中间. 我们求出 aia_i 的二阶差分 bi=ai2ai+1+ai+2b_i=a_i-2a_{i+1}+a_{i+2}. 那么对于一个长为 ss00 连续段,若 ss 为奇数,则其会使 $a_{\lfloor\frac s2\rfloor},a_{\lceil\frac s2\rceil}$ 加 11,否则会使 as2a_{\frac s2}22.

    如果把两个长为 2s12s-1 的连续段分别替换为长为 2s2,2s2s-2,2s 的连续段,那么返回的结果不变. 但是 若保证所有长为奇数的连续段长度互不相同,则可以唯一还原出每个连续段长度.


    假设我们已经找到了某个 11 的位置 ww. 考虑求出 v1kv_{1\sim k} 的值,那么我们可以这样构造:1 w 2 2 w 3 3 3 w .... 若存在一个长为 ii 的连续段,则意味着 vi=0v_i=0,否则 vi=1v_i=1. 这样一次可以查询 4343 个数的值.

    考虑如何找到第一个 11 的位置. 我们这样询问:1 1 ... 1 1 2 3 ... 100,其中 1 的个数为 100100. 若没有细菌死亡,则意味着 v1100v_{1\sim 100} 相同,可以把 1991\sim 99 扔掉变成一个大小为 n99n-99 的问题. 否则,若最后剩余细菌 <100<100,则 v1=1v_1=1,若剩余细菌 100\geq 100,则可以通过细菌存活时间推断出第一个连续段长度,从而得到第一个细菌.

    现在问题变为在 2020 次询问内查询 10001000 个数的值,也就是说每次查询我们需要得到 5050 个数.

    之前的构造中所有连续段长度互不相等,现在我们希望长为偶数的连续段出现多次. 例如,我们构造 1 12 2 w 2 23 3 w 3 3 w 3 3 w 3 3,根据长为 22 的连续段数量在二进制下每一位的值,我们可以得到 v1,v2,v3v_1,v_2,v_3 的值.

    写个程序计算可以发现可以得到 4949 个数的值. 现在还差一个数. 注意到之前我们都假设询问串开头和结尾都是 1,考虑在两端动手脚. 由于两端 00 连续段存活的时间是中间的两倍,因此我们可以把 00 连续段从中间挪到两端,然后让长度除以 22. 这样就能多询问一个数了.

    code

    #include<bits/stdc++.h>
    #include "toxic.h"
    #define fo(i,l,r) for(int i=(l);i<=(r);++i)
    #define fd(i,l,r) for(int i=(l);i>=(r);--i)
    #define fu(i,l,r) for(int i=(l);i<(r);++i)
    #define pi pair<int,int>
    #define eb emplace_back
    #define vi vector<int>
    #define fi first
    #define se second
    #define ll long long
    using namespace std;
    const int N=1007;
    int o,m,b[N],s[N],h[N];
    pi a[N];
    void determine_type(int n) {
    	fo(i,1,3)
    	{
    		int l=(i-1)*333+1,r=i*333+1;
    		vi v;
    		fo(j,1,333) v.eb(l-1);
    		fo(j,l,r) v.eb(j-1);
    		vi t=query_machine(v);
    		int w=t.back();
    		if(w==v.size()) continue;
    		if(w<333) o=l+t.size()-333;
    		else
    		{
    			o=l;
    			fo(j,1,o) s[j]=1;
    		}
    		break;
    	}
    	a[m=1]={19,1};
    	fo(i,1,50)
    	{
    		if(i&1){a[++m]={i,1};continue;}
    		fo(j,0,3) a[++m]={((i+1)<<j)-1,1<<j};
    	}
    	sort(a+2,a+m+1);
    	a[m=50]={20,1};
    	for(int r=n;r>=o;r-=50)
    	{
    		int l=r-49;
    		vi v;
    		fo(i,1,50)
    		{
    			fo(j,1,a[i].se)
    			{
    				fo(k,1,a[i].fi/a[i].se) v.eb(l+i-2);
    				v.eb(o-1);
    			}
    		}
    		v.pop_back();
    		vi w=query_machine(v);
    		b[1]=v.size()-w.back();
    		fu(i,0,w.size()) b[2+i]=w[i]-w.back();
    		fo(i,1,48) b[i]=b[i]-2*b[i+1]+b[i+2];
    		if(b[19]&1) b[19]--;
    		else s[l]=1;
    		if(b[20]&1) b[20]--;
    		else s[r]=1;
    		fd(i,18,1)
    		{
    			while(b[i]>1) b[i]-=2,h[i+i]++;
    			if(b[i]) b[i]--,b[i-1]--,h[i+i-1]++;
    		}
    		fo(i,2,49) s[l+i-1]=!(h[a[i].fi/a[i].se]&a[i].se);
    		fo(i,0,50) b[i]=h[i]=0;
    	}
    	vector<char>v;
    	fo(i,1,n) v.eb(s[i]?'T':'R');
    	answer_type(v);
    }
    
    • 1

    信息

    ID
    11009
    时间
    1000ms
    内存
    1024MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者