P1942 词编码_NOI导刊2011提高(10)

C++党的福音系列

其实这道题的题意有点乱。我在这里总结一下题意。

一个未知的01串,通过一次某种的变换,能够变成转换后的单词(输入的单词)。你的任务是倒推出转换前的单词。

可能有多解,但是正向转换的时候有考虑顺序:操作4(不改变)最优先,否则按操作1、2、3顺序为优先级。

操作2的时候先尝试删0,都不行再尝试删1。


那么我们的任务就是倒推出题意咯!

因为只有一次的变换,如果长度长于起始长度的话,一定是用了操作3,同理可以得到长度小于起始长度的情况。

我们可以使用std::string里面的两个函数很暴力地解决这个问题:

  1. std::string::insert(开始添加的下标,添加的字符串)

  2. std::string::erase(开始删除的下标,删除的长度)

然后用暴力的方法去判断一个长度满足的字符串满不满足。

但是只能够得到80pts,剩下两个点T了。


显然,劣势在于进行了太多的暴力判断。

我们使用一个技巧:后缀和。

我们维护\([i,len-1]\)这段区间的原单词有多少个1,那么删除或者添加就可以直接通过\(O(1)\)的判断就可以搞出来了。

详见代码吧,很容易看懂的。

错误思路:处理后缀和的时候,面对多组数据却忘记清空!导致直接WA!一定要小心!

代码:

#include<iostream>
#include<string>
#include<queue>
#include<cstring>
using namespace std;

const int maxn = 1005;
int suf[maxn];
int n;

bool check(string x)
{
    int res = 0, len = x.length();
    for(int i = 0; i < len; i++) if(x[i] == '1') res += i + 1;
    return res % (n + 1) == 0;
}
void solve(string word)
{
    int len = word.length();
    int res = 0;
    for(int i = 0; i < len; i++) if(word[i] == '1') res += i + 1;
    if(len == n)
    {
        if(res % (n + 1) == 0)
        {
            cout << word << endl;
            return;
        }
        for(int i = 0; i < len; i++)
        {
            if(word[i] == '1' && (res - (i + 1)) % (n + 1) == 0)
            {
                word[i] = '0';
                cout << word << endl;
                return;
            }
        }
        cout << -1 << endl;
    }
    else if(len < n)
    {
        for(int i = len - 1; i >= 0; i--) suf[i] = suf[i + 1] + (word[i] == '1');
        string temp;
        for(int i = 0; i <= len; i++)
        {
            temp = word;
            temp.insert(i, "0");
            //cout << temp << endl;
            if((res + suf[i]) % (n + 1) == 0)
            {
                cout << temp << endl;
                return;
            }
        }
        for(int i = 0; i <= len; i++)
        {
            temp = word;
            temp.insert(i, "1");
            //cout << temp << endl;
            if((res + suf[i] + i + 1) % (n + 1) == 0)
            {
                cout << temp << endl;
                return;
            }
        }
        cout << -1 << endl;
    }
    else if(len > n)
    {
        for(int i = len - 1; i >= 0; i--) suf[i] = suf[i + 1] + (word[i] == '1');
        string temp;
        for(int i = 0; i < len; i++)
        {
            temp = word;
            temp.erase(i, 1);
            if(word[i] == '1' && (res - suf[i + 1] - (i + 1)) % (n + 1) == 0)
            {
                cout << temp << endl;
                return;
            }
            if(word[i] == '0' && (res - suf[i + 1]) % (n + 1) == 0)
            {
                cout << temp << endl;
                return;
            }
        }
        cout << -1 << endl;
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin >> n;
    string word;
    while(cin >> word)
    {
        memset(suf, 0, sizeof suf);
        solve(word);
    }
    return 0;
}
posted @ 2018-11-06 09:22  Garen-Wang  阅读(162)  评论(0编辑  收藏  举报