ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

cf1697 D. Guess The String

2022-07-16 12:32:37  阅读:154  来源: 互联网

标签:字符 Guess ch String int 询问 cf1697 ans las


题意:

交互题。

猜一个小写字符串 \(s\),两种询问方式:

  • 1 i ,回答 \(s_i\) 是什么字符
  • 2 l r,回答 \(s_l\sim s_r\) 中的不同字符数量

$|s|\le 1000, $ 两种询问的次数限制分别为 \(26,6000\)

思路:

第一种询问不能超过 26 次,那肯定是先确定每种字符的分布(但不知道具体是什么字符),再询问具体是啥字符

首先可以用 \(n\) 次第二种询问得到每种字符第一次出现的位置。方法是询问 2 1 2, 2 1 3, 2 1 4 直到回答即不同字符数增大1,说明找到新段的起点。

岔路:对某 \(s_i\) 如何找到它右边最近的相同字符,即最小的 \(k>i, \text{ s.t. }s_i=s_k\) ?

发现对于两种询问 2 i j2 i+1 j-1 ,若 \(j<k\) 则前者的回答比后者大2,若 \(j=k\) 则大1,若 \(j>k\) 则相同。这样可以二分,用 \(2log_2 n\) 次确定一段,确定所有段就要 \(n*2log_2n\) 次,太多了

正确的复杂度很可能形如 \(n*()\),这个 \(n\) 应该是去不掉的。那就需要把每次找相同字符的询问次数优化到 \((6000-n)/n=5\) 次左右,而 \(\lceil log_2 26\rceil\) 刚好就是 \(5\) !

设 \(s_i\) 待确定,它左边的所有位置都已确定。把 \(s_i\) 左边出现过的每种字符 \(ch\) 按最后出现位置 \(las(ch)\) 排序。然后询问 2 las(ch) i ,若回答为 \([las(ch),i-1]\) 中的种类数 \(cnt_{ch}\),就说明 \(s_i\) 就是 \([las(ch),i-1]\) 中的某种字符;若回答是 \(cnt+1\),就说明 \(s_i\) 不在其中,得往 \(las\) 值更小的字符找。

这个 $cnt_{ch} $ 就是排序后 \(las\) 数组中 \(ch\) 到末尾的元素数

注意上面搞了这么多我们都不知道每段具体是什么字符,用一下第一种询问就好了。实际写码不必先问完第2种最后才问所有第1种,怎么方便怎么写

良心 cf 交互题的询问次数限制总是贴着正确解法的复杂度

char ask1(int i) {
    cout << "? 1 " << i << endl;
    char c; cin >> c; return c;
}
int ask2(int l, int r) {
    cout << "? 2 " << l << ' ' << r << endl;
    int v; cin >> v; return v;
}

int n; string ans;
vector<pair<int,char>> las; //{最后出现位置,字符}

int findSame(int i) {
    sort(all(las)); int len = las.size();
    int l = 0, r = len - 1; //在las里二分
    while(l < r) {
        int mid = l + r + 1 >> 1;
        if(ask2(las[mid].fi, i) == len-mid) l = mid;
        else r = mid - 1;
    }
    return l;
}
void sol() {
    cin >> n;

    ans.pb(ask1(1)), las.pb({1,ans[0]}); //先弄一下第一个

    for(int i = 2; i <= n; i++)
        if(ask2(1, i) > las.size()) //全新的字符
            ans.pb(ask1(i)), las.pb({i, ans.back()});
        else {
            int j = findSame(i); //s[j]=s[i]
            ans.pb(las[j].se), las[j].fi = i;
        }

    cout << "! " << ans << endl;
}

标签:字符,Guess,ch,String,int,询问,cf1697,ans,las
来源: https://www.cnblogs.com/wushansinger/p/16483888.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有