Educational Codeforces Round 157 (Rated for Div. 2) C D(二维map,位运算)

C - Torn Lucky Ticket

从前往后遍历字符串数组,当前遍历到的位置 j 与所有之前的位置 i (i < j) 的字符串拼接,对于每个 i 和 j,都有 (i,j) 和 (j,i) 两种拼接状态。

由于每个字符串的长度不超过5,那么对于字符串 j 可以枚举分成两半的切割位置,贡献为前面位置符合条件的字符串数。

 用二维map记录状态,mp[len][sum] = cnt 表示长度为len,每位和为 sum 的字符串有 cnt 个。

特别地,在输入后需要直接对字符串数组进行从小到大排序。因为枚举分割位置时,一半的位置只会落在较长的那个字符串上,未排序会产生遗漏。

例如数据:

2
746 5

当枚举到5时,显然分割后746的长度不满足条件。产生错误结果 2,而正确结果为3。

#include
#define double long double
#define int long long
#pragma GCC optimize(2)
using namespace std;
typedef pair PII;
const int mod = 1e9 + 7, N = 2e5 + 10;
int n, ans;
int mp[6][60];
string s[N];
void solve() 
{
    std::cin >> n;
    for (int i = 1; i <= n; i ++) std::cin >> s[i];
    std::sort(s + 1, s + n + 1, [](std::string a, std::string b) {
        return a.size() < b.size();
    });
 
    for (int i = 1; i <= n; i ++) {
        int sum = 0;
        int m = s[i].size();
        for (auto c : s[i]) sum += (c - '0');
 
        int res = 0;
        for (int j = 0, l = 1; j < s[i].size(); j ++, l ++) {
            res += (s[i][j] - '0');
 
            for (int len = 1; len <= 5; len ++) if ((l + len) == (m - l))
                    ans += mp[len][sum - res * 2];
        }
        ans += mp[m][sum] * 2;
 
        res = 0;
        for (int j = m - 1, l = 1; j >= 0; j --, l ++) {
            res += (s[i][j] - '0');
 
            for (int len = 1; len <= 5; len ++) if ((l + len) == (m - l))
                ans += mp[len][sum - res * 2];
        }
 
        ans ++;
 
        mp[m][sum] ++;
    }
 
    std::cout << ans << "\n";
}
signed main() 
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr); //cout.tie(0);
    int t = 1;// cin >> t;
    while (t--) solve();
}

D - XOR Construction

令 s[i] 为 a[1] ~ a[i] 的前缀异或,将已知条件变形可得 s[i] = b[1] ^ b[i + 1]。

观察下面式子,

s[1] = b[1] ^ b[2]

s[2] = b[1] ^ b[3]

...

s[n - 1] = b[1] ^ b[n]

s 数组已知,那么只要知道 b[1] 就能得到 b 数组。

可以根据位来处理,对于每位,等号左边该位为1的个数记为 target ,0 ~ n-1 所有数该位为1的个数记为 cnt。

当 target = cnt 时,b[1]为0;又因为一定存在b[1],故否则 b[1]为1。

#include
#define double long double
#define int long long
#pragma GCC optimize(2)
using namespace std;
typedef pair PII;
const int mod = 1e9 + 7, N = 2e5 + 10;
void solve() 
{
    int n; cin >> n;
    vectora(n + 1), b(n + 1);
    for(int i = 1; i < n; i ++) cin >> a[i];
    for(int i = 2; i < n; i ++) a[i] ^= a[i - 1];
	for(int i = 0; i <= 20; i ++)
    {
    	vectorcnt(2), target(2);
    	for(int j = 0; j < n; j ++) cnt[(j >> i) & 1] += 1;
		for(int k = 1; k < n; k ++) target[(a[k] >> i) & 1] += 1;
		if(cnt[1] != target[1]) b[1] |= (1 << i); 
	}
	for(int i = 2; i <= n; i ++) b[i] = a[i - 1] ^ b[1];
	for(int i = 1; i <= n; i ++) cout << b[i] << " ";
	cout << '\n'; 
}
signed main() 
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr); //cout.tie(0);
    int t = 1;// cin >> t;
    while (t--) solve();
}

你可能感兴趣的:(算法,数据结构)