哎,前方的路还很长。
A. Auxiliary Project
题意:考虑LED灯上显示0-9每个数字需要点亮的灯管数。给你一个n,不超过1e6,问你恰好点亮n个灯管可以点亮的数字的和,最大是多少
观察:n不是很大,可以背包。也可以找找规律,小规模打表,O(1)求解。
code:
背包

1 /* 2 by skydog 3 */ 4 #include <iostream> 5 #include <cstdio> 6 #include <vector> 7 #include <utility> 8 #include <algorithm> 9 #include <cmath> 10 #include <cstring> 11 #include <map> 12 #include <set> 13 #include <stack> 14 #include <queue> 15 #include <deque> 16 #include <cassert> 17 #include <list> 18 using namespace std; 19 typedef long long ll; 20 typedef pair<int, int> ii; 21 typedef pair<ll, ll> l4; 22 typedef unsigned long long ull; 23 #define mp make_pair 24 #define pb push_back 25 26 const int maxn = 1e6+1; 27 int f[maxn], n; 28 int c[10] = {6, 2, 5, 5, 4, 5, 6, 3, 7, 6}; 29 int main() 30 { 31 freopen("auxiliary.in", "r", stdin); 32 freopen("auxiliary.out", "w", stdout); 33 scanf("%d", &n); 34 fill(f, f+1+n, -1e9); 35 f[0] = 0; 36 for (int i = 0; i < 10; ++i) 37 for (int j = c[i]; j <= n; ++j) 38 f[j] = max(f[j], f[j-c[i]]+i); 39 printf("%d ", f[n]); 40 }
规律:

1 /* 2 by skydog 3 */ 4 #include <iostream> 5 #include <cstdio> 6 #include <vector> 7 #include <utility> 8 #include <algorithm> 9 #include <cmath> 10 #include <cstring> 11 #include <map> 12 #include <set> 13 #include <stack> 14 #include <queue> 15 #include <deque> 16 #include <cassert> 17 #include <list> 18 using namespace std; 19 typedef long long ll; 20 typedef pair<int, int> ii; 21 typedef pair<ll, ll> l4; 22 typedef unsigned long long ull; 23 #define mp make_pair 24 #define pb push_back 25 26 const int maxn = 1e6+1; 27 int f[maxn], n; 28 int c[10] = {6, 2, 5, 5, 4, 5, 6, 3, 7, 6}; 29 int cc[3] = {1, 7, 4}; 30 inline int solve(int a) 31 { 32 a -= 2; 33 return cc[a%3] + a/3*7; 34 } 35 int main() 36 { 37 freopen("auxiliary.in", "r", stdin); 38 freopen("auxiliary.out", "w", stdout); 39 scanf("%d", &n); 40 printf("%d ", solve(n)); 41 }
B. Boolean Satisfiability
题意:不超过26个boolean 变量,使用的符号只有变量名,“非”(negation)和 “或” (or)。问你有多少种赋值方式使得表达式为True。
观察:令出现的变量个数为cnt。如果一个变量x和非x同时出现,那么表达式一定为True,所有变量值随便取,答案是2^cnt。否则,至少有一个变量的值应该为True,答案是(2^cnt) - 1。
code:

1 /* 2 by skydog 3 */ 4 #include <iostream> 5 #include <cstdio> 6 #include <vector> 7 #include <utility> 8 #include <algorithm> 9 #include <cmath> 10 #include <cstring> 11 #include <map> 12 #include <set> 13 #include <stack> 14 #include <queue> 15 #include <deque> 16 #include <cassert> 17 #include <list> 18 using namespace std; 19 typedef long long ll; 20 typedef pair<int, int> ii; 21 typedef pair<ll, ll> l4; 22 typedef unsigned long long ull; 23 #define mp make_pair 24 #define pb push_back 25 26 map<char, set<int> > ma; 27 const int maxn = 1e3+1; 28 char s[maxn]; 29 int main() 30 { 31 freopen("boolean.in", "r", stdin); 32 freopen("boolean.out", "w", stdout); 33 scanf("%s", s); 34 int last = -1, ptr = 0, n = strlen(s); 35 while (ptr < n) 36 { 37 if (s[ptr] == '|'); 38 else if (s[ptr] == '~') 39 { 40 ++ptr; 41 ma[s[ptr]].insert(1); 42 } 43 else 44 { 45 ma[s[ptr]].insert(0); 46 } 47 ++ptr; 48 } 49 for (const auto &e : ma) 50 if (e.second.size() > 1) 51 { 52 printf("%lld ", 1ll<<ma.size()); 53 return 0; 54 } 55 printf("%lld ", -1 + (1ll<<ma.size())); 56 57 }
C. Consonant Fencity
题意:给你一个长度不超过1e6的只有小写字母组成的字符串。定义aeiouwy这7个字母为元音,其余的字母为辅音。对于一个字符串,它的美丽度是相邻且大小写不同的辅音对的个数。允许你把一些字母变成大写(同一种字母大小写必须相同),让你输出美丽值最大的字符串。
观察:辅音有19个,可以暴力枚举19个大小写情况,每次检查有多少个美丽的辅音对。暴力枚举是2^19。但是因为大小写颠倒不影响答案,其实可以固定某一个辅音的大小写,枚举剩下18个的大小写,2^18。然后辅音对可以用一个int cnt[19][19]预处理出来,对于每一种大小写情况,19*19的暴力统计。
code:

1 /* 2 by skydog 3 */ 4 #include <iostream> 5 #include <cstdio> 6 #include <vector> 7 #include <utility> 8 #include <algorithm> 9 #include <cmath> 10 #include <cstring> 11 #include <map> 12 #include <set> 13 #include <stack> 14 #include <queue> 15 #include <deque> 16 #include <cassert> 17 #include <list> 18 using namespace std; 19 typedef long long ll; 20 typedef pair<int, int> ii; 21 typedef pair<ll, ll> l4; 22 typedef unsigned long long ull; 23 #define mp make_pair 24 #define pb push_back 25 26 const string vowel = "aeiouwy"; 27 int s[300]; 28 char id[30]; 29 int cnt[30][30]; 30 char str[1000001]; 31 int solve(int mask) 32 { 33 int ans = 0; 34 for (int i = 1; i <= s['z']; ++i) 35 for (int j = 1; j <= s['z']; ++j) 36 if (((mask>>i-1)&1)^((mask>>j-1)&1)) 37 { 38 //if (cnt[i][j]) cerr << id[i] << " " << id[j] << " " << cnt[i][j] << endl; 39 ans += cnt[i][j]; 40 } 41 return ans; 42 } 43 /* 44 16436 45 */ 46 char perm[300]; 47 int main() 48 { 49 freopen("consonant.in", "r", stdin); 50 freopen("consonant.out", "w", stdout); 51 for (char c = 'a'; c <= 'z'; ++c) 52 s[c] = 1; 53 for (auto c : vowel) 54 s[c] = 0; 55 int tot = 0; 56 for (char c = 'a'; c <= 'z'; ++c) 57 if (s[c]) 58 { 59 s[c] = ++tot; 60 } 61 for (char c = 'a'; c <= 'z'; ++c) 62 if (s[c]) 63 id[s[c]] = c; 64 scanf("%s", str); 65 int n = strlen(str); 66 for (int i = 0; i < n-1; ++i) 67 cnt[s[str[i]]][s[str[i+1]]] += 1; 68 int ans = 0, mask = 0; 69 for (int i = 0; i < (1<<18); ++i) 70 { 71 int tmp = solve(i); 72 if (tmp > ans) 73 ans = tmp, mask = i; 74 } 75 for (char c = 'a'; c <= 'z'; ++c) 76 perm[c] = c; 77 for (int i = 1; i <= s['z']; ++i) 78 if ((mask>>i-1)&1) 79 perm[id[i]] = id[i]+'Z'-'z'; 80 for (int i = 0; i < n; ++i) 81 putchar(perm[str[i]]); 82 puts(""); 83 84 }
D. Dividing Marbles
E. Equal Numbers
题意:给你一个长度不超过3e5,元素都不超过1e6的正整数数列a[]。一次操作允许你将其中一个元素乘上任意一个正整数。对于k = 0,1,2, ..., n,让你输出进行k次操作,数列中不同数值个数的最小值。
观察:当k = n时,我们一定可以使所有元素相同,即把所有数都变成a[1] - a[n]的一个公倍数CM。所以操作可以简化成两类,一类是将某个a[i] 变成一个数列中存在的a[j],为了方便理解可以直接把a[j]选作数列中出现的a[i]倍数里最大的一个;或者把某个a[i]变成最终的CM。这样的话,也就可以把数列中初始的数分成两类,有后继的数(后继指数列中出现的自己的倍数)和没后继的数。注意,为了使不同数值的个数降低,我们需要把某一个数值的所有元素一起变换才会有效,所以要贪心的取出现次数最少的。计算答案的时候只需要考虑两种情况,就是CM已经出现,或者CM还未出现。
方法:为了图省事,写了前缀和加二分答案。其实是可以使用滑动窗口来做。
code:
下面第一种写法的意思是,要么不考虑生成CM。如果考虑生成CM,就一定要至少取一个没有后继的数。

1 /* 2 by skydog 3 */ 4 #include <iostream> 5 #include <cstdio> 6 #include <vector> 7 #include <utility> 8 #include <algorithm> 9 #include <cmath> 10 #include <cstring> 11 #include <map> 12 #include <set> 13 #include <stack> 14 #include <queue> 15 #include <deque> 16 #include <cassert> 17 #include <list> 18 using namespace std; 19 typedef long long ll; 20 typedef pair<int, int> ii; 21 typedef pair<ll, ll> l4; 22 typedef unsigned long long ull; 23 #define mp make_pair 24 #define pb push_back 25 26 const int maxn = 1e6+1; 27 int cnt[maxn], n; 28 int main() 29 { 30 freopen("equal.in", "r", stdin); 31 freopen("equal.out", "w", stdout); 32 scanf("%d", &n); 33 for (int i = 0; i < n; ++i) 34 { 35 int x; 36 scanf("%d", &x); 37 ++cnt[x]; 38 } 39 vector<int> a, b; 40 for (int i = 1; i < maxn; ++i) 41 if (cnt[i]) 42 { 43 bool done = false; 44 for (int j = 2*i; j < maxn; j += i) 45 if (cnt[j]) 46 { 47 done = true; 48 break; 49 } 50 if (done) 51 b.pb(cnt[i]); 52 else 53 a.pb(cnt[i]); 54 } 55 int tot = a.size() + b.size(); 56 swap(a.back(), *min_element(a.begin(), a.end())); 57 int mini = a.back(); 58 a.pop_back(); 59 b.pb(0); 60 a.insert(a.end(), b.begin(), b.end()); 61 sort(a.begin(), a.end()); 62 sort(b.begin(), b.end()); 63 for (int i = 1; i < a.size(); ++i) 64 a[i] += a[i-1]; 65 for (int j = 1; j < b.size(); ++j) 66 b[j] += b[j-1]; 67 for (int i = 0; i <= n; ++i) 68 { 69 int ans = tot - max(upper_bound(a.begin(), a.end(), i-mini)-a.begin()-1,(upper_bound(b.begin(), b.end(), i)-b.begin()-1)); 70 printf("%d%c", ans, i==n?' ':' '); 71 } 72 73 }
反思之后下面第二种写法会比较容易理解,即要么不考虑生成CM,要么生成CM,但是会浪费一次变换的机会(因为CM原本未在数列中出现,第一次把一类数变成CM不会使答案下降)。

1 /* 2 by skydog 3 */ 4 #include <iostream> 5 #include <cstdio> 6 #include <vector> 7 #include <utility> 8 #include <algorithm> 9 #include <cmath> 10 #include <cstring> 11 #include <map> 12 #include <set> 13 #include <stack> 14 #include <queue> 15 #include <deque> 16 #include <cassert> 17 #include <list> 18 using namespace std; 19 typedef long long ll; 20 typedef pair<int, int> ii; 21 typedef pair<ll, ll> l4; 22 typedef unsigned long long ull; 23 #define mp make_pair 24 #define pb push_back 25 26 const int maxn = 1e6+1; 27 int cnt[maxn], n; 28 int main() 29 { 30 freopen("equal.in", "r", stdin); 31 freopen("equal.out", "w", stdout); 32 scanf("%d", &n); 33 for (int i = 0; i < n; ++i) 34 { 35 int x; 36 scanf("%d", &x); 37 ++cnt[x]; 38 } 39 vector<int> a, b; 40 for (int i = 1; i < maxn; ++i) 41 if (cnt[i]) 42 { 43 for (int j = 2*i; j < maxn; j += i) 44 if (cnt[j]) 45 { 46 b.pb(cnt[i]); 47 break; 48 } 49 a.pb(cnt[i]); 50 } 51 int tot = a.size(); 52 b.pb(0); 53 a.pb(0); 54 sort(a.begin(), a.end()); 55 sort(b.begin(), b.end()); 56 for (int i = 1; i < a.size(); ++i) 57 a[i] += a[i-1]; 58 for (int j = 1; j < b.size(); ++j) 59 b[j] += b[j-1]; 60 for (int i = 0; i <= n; ++i) 61 { 62 int ans = tot - max(upper_bound(a.begin(), a.end(), i)-a.begin()-2,(upper_bound(b.begin(), b.end(), i)-b.begin()-1)); 63 printf("%d%c", ans, i==n?' ':' '); 64 } 65 66 }
I. Intelligence in Perpendicularia
题意:给你一个不超过1000个点的简单多边形。每条边水平或者竖直。问你用不能从沿x轴或者y轴看到的边长有多少。
观察:其实就是多边形周长长减去最小外接长方形的周长。
code:

1 /* 2 by skydog 3 */ 4 #include <iostream> 5 #include <cstdio> 6 #include <vector> 7 #include <utility> 8 #include <algorithm> 9 #include <cmath> 10 #include <cstring> 11 #include <map> 12 #include <set> 13 #include <stack> 14 #include <queue> 15 #include <deque> 16 #include <cassert> 17 #include <list> 18 using namespace std; 19 typedef long long ll; 20 typedef pair<int, int> ii; 21 typedef pair<ll, ll> l4; 22 typedef unsigned long long ull; 23 #define mp make_pair 24 #define pb push_back 25 26 const int maxn = 1e3+1; 27 int x[maxn], y[maxn], n; 28 29 int main() 30 { 31 freopen("intel.in", "r", stdin); 32 freopen("intel.out", "w", stdout); 33 scanf("%d", &n); 34 for (int i = 0; i < n; ++i) 35 scanf("%d %d", x+i, y+i); 36 int ans = 0; 37 for (int i = 0; i < n; ++i) 38 ans += abs(x[(i+1)%n]-x[i]) + abs(y[(i+1)%n]-y[i]); 39 ans -= 2*(*max_element(x, x+n)-*min_element(x, x+n) + *max_element(y, y+n)-*min_element(y, y+n)); 40 printf("%d ", ans); 41 }
K. Kotlin Island
题意:在一块h*w的土地上(h,w <=100),你可以横向或者纵向挖水沟。给你一个n,不超过1e9,让你输出一种使得水沟外,剩下陆地联通块个数为n的方案。
观察:对于一个纬度x,最多可以将其分成(x+1)/2条(切(x-1)/2刀)。所以可以如果可以把n分解成a*b的形式,且 min(a, b) <= (min(w, h)+1)/2, max(a, b) <= (max(w, h)+1)/2,那么就有解。
code:

1 /* 2 by skydog 3 */ 4 #include <iostream> 5 #include <cstdio> 6 #include <vector> 7 #include <utility> 8 #include <algorithm> 9 #include <cmath> 10 #include <cstring> 11 #include <map> 12 #include <set> 13 #include <stack> 14 #include <queue> 15 #include <deque> 16 #include <cassert> 17 #include <list> 18 using namespace std; 19 typedef long long ll; 20 typedef pair<int, int> ii; 21 typedef pair<ll, ll> l4; 22 typedef unsigned long long ull; 23 #define mp make_pair 24 #define pb push_back 25 26 27 const int maxn = 1e2+1; 28 char s[maxn][maxn]; 29 int w, h, n; 30 void solve(int wl, int hl) 31 { 32 --wl, --hl; 33 for (int i = 1; i <= wl; ++i) 34 for (int j = 0; j < h; ++j) 35 s[2*i-1][j] = '#'; 36 for (int j = 1; j <= hl; ++j) 37 for (int i = 0; i < w; ++i) 38 s[i][2*j-1] = '#'; 39 for (int i = 0; i < w; ++i) 40 puts(s[i]); 41 exit(0); 42 } 43 int main() 44 { 45 freopen("kotlin.in", "r", stdin); 46 freopen("kotlin.out", "w", stdout); 47 scanf("%d %d %d", &w, &h, &n); 48 for (int i = 0; i < w; ++i) 49 { 50 fill(s[i], s[i]+h, '.'); 51 s[i][h] = 0; 52 } 53 int wl = (w+1)/2, hl = (h+1)/2; 54 for (int i = 1; i <= wl; ++i) 55 if (n%i == 0 && n/i <= hl) 56 solve(i, n/i); 57 puts("Impossible"); 58 }
L. Little Difference
题意:给你一个n,不超过1e18。让你把n分解成若干正因子的积,且任意两个因子间差不超过1。让你以任意顺序输出所有方案,如果有无限种方案,输出-1。
观察:如果n是2的自然数幂,那么n有无穷组分解,因为可以在分解中加任意个数的1。其他情况都有有限解。注意到{n}本身是一个解,然后如果分解成两个数,那么其中一定有一个是ceil(sqrt(n)),特判一下这种情况。最后如果解中的元素不少于3个,那么最小的元素肯定不超过1e6,暴力枚举每一个最小的元素即可。
code:

1 /* 2 by skydog 3 */ 4 #include <iostream> 5 #include <cstdio> 6 #include <vector> 7 #include <utility> 8 #include <algorithm> 9 #include <cmath> 10 #include <cstring> 11 #include <map> 12 #include <set> 13 #include <stack> 14 #include <queue> 15 #include <deque> 16 #include <cassert> 17 #include <list> 18 using namespace std; 19 typedef long long ll; 20 typedef pair<int, int> ii; 21 typedef pair<ll, ll> l4; 22 typedef unsigned long long ull; 23 #define mp make_pair 24 #define pb push_back 25 26 vector<vector<ll> > ans; 27 ll n; 28 void test(ll x, ll n) 29 { 30 if (x == 1 || n % x != 0) 31 return; 32 vector<ll> v; 33 while (n % x == 0) 34 n /= x, v.pb(x); 35 while (n % (x+1) == 0) 36 n /= x+1, v.pb(x+1); 37 if (n == 1) 38 ans.pb(v); 39 } 40 bool pow2(ll n) 41 { 42 while (n % 2 == 0) 43 n >>= 1; 44 return n == 1; 45 } 46 int main() 47 { 48 //freopen("little.in", "r", stdin); 49 //freopen("little.out", "w", stdout); 50 scanf("%lld", &n); 51 if (pow2(n)) 52 { 53 puts("-1"); 54 return 0; 55 } 56 ans.pb({n}); 57 ll root = sqrt(n+0.5); 58 while (root*root <= n) 59 ++root; 60 while (root*root > n) 61 --root; 62 test(root, n); 63 for (ll i = 2; i*i*i <= n; ++i) 64 test(i, n); 65 printf("%d ", ans.size()); 66 for (const auto &v : ans) 67 { 68 printf("%d", v.size()); 69 for (const auto e : v) 70 printf(" %lld", e); 71 putchar(' '); 72 } 73 }