NOI模擬(5.7) HNOID1T1 尋寶遊戲 (bzoj5285)

尋寶遊戲

題目背景:

5.7 模擬 HNOI2018D1T1  

分析:思維分析

 

這道題感覺真的是很厲害的一道題,當時考場上因爲的確不知道怎麼做,於是就手玩了一下小數據,然後就發現,如果把|看成是0&看成是1的話,以第n個數之前的符號當成最高位,這樣每一種填符號的方案就是一個n位二進制數,然後發現對於可行的符號方案,一定是一段連續的二進制數。並且這些可行解中最小的一個一定是將原來的n個數的相同位置提取出來,從n1形成的m個二進制數中的一個,而上界是這m個數中的一個減去1,然後又繼續找發現了下邊界的對應位置一定是結果串中爲0的位置,上邊界是爲1的位置,然後下邊界是0當中最大的,上邊界是1當中最小的,就這麼一步步找規律搞了出來,最後竟然還真的是對的······考慮系統證明一下,首先像我之前說的那樣,每一種符號填法形成一個n位二進制數,然後n個原數提取每一位形成m個二進制數,最高位都是第n位,難麼我們可以對於每一位分開考慮,顯然,|0,或者是&1是沒有用的,如果最終位爲1,那麼最後一個|1一定在最後一個&0之後,反之亦然,所以考慮這在二進制數上的體現,我們從高位向下比較運算符字符串,和形成的當前位字符串,如果兩者當前位置相同,則不影響,如果第一個不同的位置,運算符爲1,原位置串爲0,那麼最終這一位結果就是0,否則結果爲1,如果兩串相同,結果還是爲0,那麼對於最終位置是1的地方,運算符串顯然要比當前位置串小,而如果最終位置是0的話,運算符串顯然要大於等於當前位置串,所以我們只需要每一次找出最終位是0的位置串中最大的一個,已經最終位是1的位置串中最小的一個,後減前即爲答案,注意判無解的情況即可。

 

Source:

/*
    created by scarlyw
*/
#include <cstdio>
#include <string>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
#include <cctype>
#include <vector>
#include <set>
#include <queue>
#include <ctime>
#include <bitset>
 
inline char read() {
    static const int IN_LEN = 1024 * 1024;
    static char buf[IN_LEN], *s, *t;
    if (s == t) {
        t = (s = buf) + fread(buf, 1, IN_LEN, stdin);
        if (s == t) return -1;
    }
    return *s++;
}
 
/*
template<class T>
inline void R(T &x) {
    static char c;
    static bool iosig;
    for (c = read(), iosig = false; !isdigit(c); c = read()) {
        if (c == -1) return ;
        if (c == '-') iosig = true; 
    }
    for (x = 0; isdigit(c); c = read()) 
        x = ((x << 2) + x << 1) + (c ^ '0');
    if (iosig) x = -x;
}
//*/

const int OUT_LEN = 1024 * 1024;
char obuf[OUT_LEN];
char *oh = obuf;
inline void write_char(char c) {
	if (oh == obuf + OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf;
	*oh++ = c;
}


template<class T>
inline void W(T x) {
	static int buf[30], cnt;
	if (x == 0) write_char('0');
	else {
		if (x < 0) write_char('-'), x = -x;
		for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 + 48;
		while (cnt) write_char(buf[cnt--]);
	}
}

inline void flush() {
    for (int i = 0; i <= 10; ++i) std::cout << obuf[i];
    std::cout << '\n';
	fwrite(obuf, 1, oh - obuf, stdout), oh = obuf;
}
 
// /*
template<class T>
inline void R(T &x) {
    static char c;
    static bool iosig;
    for (c = getchar(), iosig = false; !isdigit(c); c = getchar())
        if (c == '-') iosig = true; 
    for (x = 0; isdigit(c); c = getchar()) 
        x = ((x << 2) + x << 1) + (c ^ '0');
    if (iosig) x = -x;
}
//*/

const int MAXN = 1000 + 9;
const int MAXM = 5000 + 9;
const int mod = 1000000000 + 7;

int n, m, q;
int sum[MAXM], rk[MAXM], temp[MAXM];
char s[MAXM];

int main() {
    //freopen("hunt.in", "r", stdin);
    //freopen("hunt.out", "w", stdout);
    R(n), R(m), R(q);
    int ret = 1;
    for (int i = 0; i <= m + 1; ++i) rk[i] = i;
    for (int i = 0; i < n; ++i, ret = ret * 2 % mod) {
        scanf("%s", s + 1);
        for (int j = 1; j <= m; ++j) 
            sum[j] = (sum[j] + (s[j] - '0') * ret) % mod;
        for (int j = 1, h = 0; j <= m; ++j)
            if (s[rk[j]] - '0') temp[++h] = rk[j];
        for (int j = m, t = m + 1; j >= 1; --j)
            if ((s[rk[j]] - '0') == 0) temp[--t] = rk[j];
        // for (int j = 1; j <= m; ++j) std::cout << temp[j] << " ";
        for (int j = 1; j <= m; ++j) rk[j] = temp[j];
    }
    // for (int i = 1; i <= m; ++i) std::cout << rk[i] << " ";
    // std::cout << '\n';
    sum[0] = ret, sum[m + 1] = 0;
    while (q--) {
        scanf("%s", s + 1);
        int p0 = m + 1, p1 = 0;
        for (int j = m; j >= 1; --j)
            if (s[rk[j]] - '0') {
                p1 = j;
                break ;
            } 
        for (int j = 1; j <= m; ++j)
            if ((s[rk[j]] - '0') == 0) {
                p0 = j;
                break ;
            }
        if (p0 <= p1) {
            puts("0");
            continue ;
        }
        std::cout << (sum[rk[p1]] - sum[rk[p0]] + mod) % mod << '\n';
    }
    return 0;
}

 

 

 

 

 

 

 

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章