1. 程式人生 > >P1942 詞編碼_NOI導刊2011提高(10)

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;
}