题外话
鸽了好久,忙学校的一堆b课和b考试,打了CF也没写题解。打场div2复健一下。
完成情况
赛时
YES
YES
YES
NO
NO
补题
YES
NO
直觉法可得能凑成的充要条件是\((n>m)
\land (n\equiv m \mod 2)\) 。
考虑对于二进制下一段连续的1,设第一位为\(i\) 位,最后一位为\(j\) 位,给\(j+1\) 设为1,再给\(i\) 设为-1。
可以发现两个特殊情况会出现两个连续的非0,一是两段连续的1只有一个0隔开。设低位的连续段位\([i, p]\) ,高位的为\([p+2, j]\) 。我们要将\(p+1\) 位置为1,\(p+2\) 位置为-1,那么显然可以替换成将\(p+1\) 位置为-1。
二是单独一个1的连续段。这种情况下直接将\(i\) 置为1,然后考虑用上面类似的策略和低位的1进行等效替换即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 #include <bits/stdc++.h> using namespace std; const int N = 2e5 + 10 ;const int inf = 1 << 30 ;const long long llinf = 1ll << 60 ;const double PI = acos (-1 ); #define lowbit(x) (x&-x) typedef long long ll;typedef double db;typedef pair<int , int > pii;typedef pair<ll, ll> pll;typedef pair<db, db> pdd;typedef pair<ll, int > pli; int n, m, k, q;int a[40 ];void work () { int x; cin >> x; int n = 0 ; memset (a, 0 , sizeof a); for (int i = 0 ; i < 32 ; i++) { if (((x >> i) & 1 ) == 0 ) continue ; int j = i; while ((x >> j) & 1 ) j++; if (i + 1 == j) { if (i != 0 && a[i - 1 ] != 0 ) { a[j] = 1 ; a[i - 1 ] = -1 ; n = j + 1 ; continue ; } a[i] = 1 ; n = i + 1 ; continue ; } a[j] = 1 ; if (a[i - 1 ] == 0 ) a[i] = -1 ; else a[i - 1 ] = -1 ; i = j; n = j + 1 ; } cout << n << '\n' ; for (int i = 0 ; i < n; i++) cout << a[i] << " \n" [i == n - 1 ]; } int main () { ios::sync_with_stdio (0 ); cin.tie (0 ); cout.tie (0 ); int t; cin >> t; while (t --> 0 ) { work (); } }
手玩数据可以发现,当序列所有数的\(lcm\) 比最大的数还要大时,显然答案一定为n。反之,\(lcm\) 就一定等于最大的那个数。同时,\(a\) 中所有的数一定都是\(a_n\) 的因子,能凑出来的\(lcm\) 也一定是\(a_n\) 的因子。
排序后,我们暴力枚举\(a_n\) 的因子\(d\) ,判断它有没有在\(a\) 中出现后让它作为最终答案的目标\(lcm\) ,然后枚举\(a_i\) 看它是不是\(d\) 的因子,有就合并\(lcm'\) 。然后检查\(lcm'\) 是否等于\(d\) ,等于的话就直接更新答案。复杂度\(O(n^2)\) 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 #include <bits/stdc++.h> using namespace std;const int N = 2e5 + 10 ;const int inf = 1 << 30 ;const long long llinf = 1ll << 60 ;const double PI = acos (-1 );#define lowbit(x) (x&-x) typedef long long ll;typedef double db;typedef pair<int , int > pii;typedef pair<ll, ll> pll;typedef pair<db, db> pdd;typedef pair<ll, int > pli;int n, m, k, q;ll a[N]; void work () { cin >> n; ll sum = 1 ; map<ll, int > s; bool ok = 0 ; for (int i = 1 ; i <= n; i++) { cin >> a[i]; s[a[i]]++; sum = sum * a[i] / __gcd(sum, a[i]); if (sum > (ll)(1e9 )) ok = 1 ; } sort (a + 1 , a + n + 1 ); if (sum != a[n] || ok) { cout << n << '\n' ; return ; } vector<ll> vec; for (int i = 1 ; i * i <= sum; i++) { if (sum % i == 0 ) { vec.push_back (i); if (i * i != sum) vec.push_back (sum / i); } } int ans = 0 ; for (auto maxn : vec) { if (s[maxn] != 0 ) continue ; ll s1 = 1 ; int cnt = 0 ; for (int i = 1 ; i <= n; i++) { if (__gcd(a[i], maxn) == a[i]) cnt++, s1 = (ll)s1 * a[i] / __gcd(a[i], s1); } if (s1 == maxn) ans = max (ans, cnt); } cout << ans << '\n' ; } int main () { ios::sync_with_stdio (0 ); cin.tie (0 ); cout.tie (0 ); int t; cin >> t; while (t --> 0 ) { work (); } }
可以发现一个性质:当我们指定了对于第\(j\) 列对答案有贡献,且第\(i\) 行的数字为1时,此时的构造方案唯一确定也就是说,最多只有\(n\times m\) 种不同的有效方案可以选择。
考虑枚举令\([i,j]\) 上的数字为此列唯一的1,\(\text{Hash}\) 算出此时的具体方案,然后全部扔进一个map
里,最后选取出现次数最多的那个方案。时间复杂度\(\Theta(nmlog_2(nm))\) ,用unordered_map
能降到\(\Theta(nm)\) 。
注意本题卡单哈希,算方案时记得用双哈希。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 #include <bits/stdc++.h> using namespace std;const int N = 5e5 + 10 ;const int inf = 1 << 30 ;const long long llinf = 1ll << 60 ;const double PI = acos (-1 );#define lowbit(x) (x & -x) typedef long long ll;typedef double db;typedef pair<int , int > pii;typedef pair<ll, ll> pll;typedef pair<db, db> pdd;typedef pair<ll, int > pli;int n, m, k, q;uint64_t pw1[N], pw2[N];const uint64_t mod1 = 1000000007ULL ;const uint64_t mod2 = 1000000009ULL ;struct myHash { uint64_t hash1, hash2; myHash () { hash1 = hash2 = 0 ; } }; myHash changePos (myHash hash, int pos, bool originVal, bool newVal) { if (originVal) { hash.hash1 = (hash.hash1 - pw1[pos] + mod1) % mod1; hash.hash2 = (hash.hash2 - pw2[pos] + mod2) % mod2; } if (newVal) { hash.hash1 = (hash.hash1 + pw1[pos]) % mod1; hash.hash2 = (hash.hash2 + pw2[pos]) % mod2; } return hash; } uint64_t toNormal (myHash hash) { uint64_t h1 = hash.hash1, h2 = hash.hash2; return (h1 << 31ULL ) | h2; } void work () { cin >> n >> m; vector<vector<int >> a (n, vector <int >(m)); for (int i = 0 ; i < n; i++) { string s; cin >> s; for (int j = 0 ; j < m; j++) a[i][j] = s[j] - '0' ; } unordered_map<uint64_t , int > s; int ans = 0 ; string ans_str; for (int j = 0 ; j < m; j++) { myHash hsh; string str; for (int i = 0 ; i < n; i++) { hsh = changePos (hsh, i, 0 , a[i][j]); str.push_back (a[i][j] + '0' ); } for (int i = 0 ; i < n; i++) { if (i != 0 ) { hsh = changePos (hsh, i - 1 , !a[i - 1 ][j], a[i - 1 ][j]); str[i - 1 ] = '0' + (char )(str[i - 1 ] == '0' ); } hsh = changePos (hsh, i, a[i][j], !a[i][j]); str[i] = '0' + (char )(str[i] == '0' ); int p = ++s[toNormal (hsh)]; if (p > ans) { ans = p; ans_str = str; } } } cout << ans << '\n' << ans_str << '\n' ; } int main () { ios::sync_with_stdio (0 ); cin.tie (0 ); cout.tie (0 ); pw1[0 ] = pw2[0 ] = 1 ; for (int i = 1 ; i < N; i++) { pw1[i] = (pw1[i - 1 ] * 2ULL ) % mod1; pw2[i] = (pw2[i - 1 ] * 2ULL ) % mod2; } int t; cin >> t; while (t-- > 0 ) { work (); } }