http://codeforces.com/contest/1207
B. Square Filling
题意:一个nm的01矩阵,要求在一个初始为0的nm矩阵中操作,每次选一个2*2的正方形置为1,问能否得到和给定矩阵一样的矩阵。
遍历,贪心地判断如果当前位置的正方形内都是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 #include <bits/stdc++.h> using namespace std;#define ll long long const int N = 2e5 + 10 ;const int INF = 0x3f3f3f3f ;int n, m;int a[100 ][100 ], b[100 ][100 ];typedef pair<int , int > pii;vector<pii>vc; int cal () { int ans = 0 ; for (int i = 1 ; i <= n; i++) { for (int j = 1 ; j <= m; j++) { if (a[i][j] && a[i + 1 ][j] && a[i][j + 1 ] && a[i + 1 ][j + 1 ]) { b[i][j] = b[i + 1 ][j] = b[i][j + 1 ] = b[i + 1 ][j + 1 ] = 1 ; vc.push_back (pii (i, j)); ans++; } } } for (int i = 1 ; i <= n; i++)for (int j = 1 ; j <= m; j++) if (a[i][j] != b[i][j])return -1 ; return ans; } int main () { scanf ("%d%d" , &n, &m); for (int i = 1 ; i <= n; i++) { for (int j = 1 ; j <= m; j++) { scanf ("%d" , &a[i][j]); } } int ans = cal (); if (ans == -1 )puts ("-1" ); else { printf ("%d\n" , ans); for (pii p : vc) { printf ("%d %d\n" , p.first, p.second); } } return 0 ; }
C. Gas Pipeline
题意:一个线段按照整点分成了n格,每格是0或1,若是1,则这一格高度必须是2,问最小花费。
dp
d p [ i ] [ 0 / 1 ] dp[i][0/1] d p [ i ] [ 0/1 ] 表示这格高度是0或1时最小花费,简单dp,要注意端点处理即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #include <bits/stdc++.h> using namespace std;#define ll long long const int N = 2e5 + 10 ;const int INF = 0x3f3f3f3f ;const ll inf = 1e18 ;int T, n; ll a, b;ll dp[N][2 ]; int main () { scanf ("%d" , &T); while (T--) { scanf ("%d%lld%lld" , &n, &a, &b); for (int i = 1 ; i <= n; i++)dp[i][0 ] = dp[i][1 ] = inf; for (int i = 1 ; i <= n; i++) { char c; scanf (" %c" , &c); if (c == '0' ) dp[i][0 ] = min (dp[i - 1 ][0 ] + b, dp[i - 1 ][1 ] + a + b); if (i != 1 )dp[i][1 ] = min (dp[i - 1 ][1 ] + 2 * b, dp[i - 1 ][0 ] + a + 3 * b); } printf ("%lld\n" , dp[n][0 ] + n * a + b); } return 0 ; }
D. Number Of Permutations
题意:给定一个pair数组,问有几种排列满足第一维不是非递减,且第二维也不是非递减。
容斥原理
总的排列数-第一维非递减-第二维非递减+第一第二维都非递减。
一个非递减数列,相同的数之间交换,仍然非递减,所以就是相同的数的个数的排列。至于第一第二维都非递减则要固定第一维相同,再看第二维。如果最大的数比下一段最小的数大,那一定不满足。
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 #include <bits/stdc++.h> using namespace std;#define ll long long const int N = 3e5 + 10 ;const int INF = 0x3f3f3f3f ;const ll mod = 998244353 ;int n;typedef pair<int , int >pii;pii a[N]; ll fac[N], ans = 1 , cnt[2 ][N]; map<int , int >mp; int main () { scanf ("%d" , &n); fac[0 ] = 1 ; for (int i = 1 ; i <= n; i++)fac[i] = fac[i - 1 ] * i%mod; for (int i = 1 ; i <= n; i++) { scanf ("%d%d" , &a[i].first, &a[i].second); cnt[0 ][a[i].first]++, cnt[1 ][a[i].second]++; } ll tmp1 = 1 , tmp2 = 1 , tmp3 = 1 ; for (int i = 1 ; i <= n; i++) { tmp1 = tmp1 * fac[cnt[0 ][i]] % mod; tmp2 = tmp2 * fac[cnt[1 ][i]] % mod; } sort (a + 1 , a + n + 1 ); int mx = 0 ; for (int i = 1 ; i <= n; i++) { mp[a[i].second]++; if (a[i].second < mx) { tmp3 = 0 ; break ; } if (a[i].first != a[i + 1 ].first) { mx = 0 ; for (pii p : mp) { tmp3 = tmp3 * fac[p.second]%mod; mx = max (mx, p.first); } mp.clear (); } } ans = (fac[n] - tmp1 - tmp2 + tmp3 + 2 * mod) % mod; printf ("%lld\n" , ans); return 0 ; }
E. XOR Guessing
题意:交互题,要猜一个数,0 ≤ x < 2 14 0\leq x<2^{14} 0 ≤ x < 2 14 ,最多两次询问,每次询问给出100个数字,评测机会随机挑1个,返回它和这个数的异或值。
被样例带歪了。。
其实很简单,只要先用前半部分全是0的数,得到答案的前半部分,再用后半部分全是0的数,得到答案的后边部分。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include <bits/stdc++.h> using namespace std;#define ll long long const int N = 3e5 + 10 ;const int INF = 0x3f3f3f3f ;int a, b;int main () { cout << '?' ; for (int i = 1 ; i <= 100 ; i++)cout << ' ' << i; cout << endl; cin >> a; cout << '?' ; for (int i = 1 ; i <= 100 ; i++)cout << ' ' << (i << 7 ); cout << endl; cin >> b; int ans = 0 ; for (int i = 0 ; i < 7 ; i++)if (b&(1 << i))ans |= (1 << i); for (int i = 7 ; i < 14 ; i++)if (a&(1 << i))ans |= (1 << i); cout << "! " << ans << endl; return 0 ; }
F. Remainder Problem
题意:一个长度为5e5的数组,两种操作:a x + = y a_x+=y a x + = y ;询问下标mod x=y的所有位置的值之和。
分块
如果询问的x大于1 0 5 \sqrt{10^5} 1 0 5 ,则暴力统计,单次复杂度不超过 1 0 5 \sqrt{10^5} 1 0 5 。
预处理 s u m [ i ] [ j ] sum[i][j] s u m [ i ] [ j ] 表示所有下标mod i=j的位置的值之和,每次操作1时更新所有i。单次更新复杂度为 1 0 5 \sqrt{10^5} 1 0 5 ,询问时直接拿出来。
总的复杂度 O ( q 1 0 5 ) \mathcal{O}(q\sqrt{10^5}) O ( q 1 0 5 )
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 #include <bits/stdc++.h> using namespace std;#define ll long long const int N = 5e5 + 10 ;const int INF = 0x3f3f3f3f ;int q, op, x, y;ll sum[1010 ][1010 ]; int a[N];int main () { scanf ("%d" , &q); int b = (int )sqrt (500000 ); while (q--) { scanf ("%d%d%d" , &op, &x, &y); if (op == 1 ) { a[x] += y; for (int i = 1 ; i <= b; i++) sum[i][x%i] += y; } else { ll ans = 0 ; if (x <= b)ans = sum[x][y]; else for (int i = y; i <= 500000 ; i += x) ans += a[i]; printf ("%lld\n" , ans); } } return 0 ; }