AtCoder Regular Contest 088
C - Multiple Gift
输出$log_2\frac{y}{x}$。
1 #include<cstdio> 2 #include<iostream> 3 using namespace std; 4 typedef long long ll; 5 int main() { 6 ll a, b, res = 0; 7 cin >> a >> b; 8 for (b /= a; b; b >>= 1, ++res); 9 cout << res << endl; 10 return 0; 11 }
D - Wide Flip
简要题意:有一个长度为$n(n<=10^5)$的01串,你需要找到一个最大的$k$使得在若干次操作后所有的1都能变成0。
操作:选择一段连续的区间$[l,r]$$(r - l + 1 \geqslant k)$,并把上面所有的0变成1,1变成0。
现在咱来看看怎么做这道题。
假设$s_i \neq s_{i+1}$,为了让他们相同咱可以对$[1,i]$和$[1,i+1]$或$[i,n]$和$[i+1,n]$同时进行操作,所以$ans=max\{min\{i, n-i\},s_i \neq s_{i+1}\}$
时间复杂度$O(n)$
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 using namespace std; 5 char s[100010]; 6 int n, ans; 7 int main() { 8 scanf("%s", s + 1); 9 ans = n = strlen(s + 1); 10 for (int i = 1; i < n; ++i) 11 if (s[i] != s[i+1]) 12 ans = min(ans, max(i, n - i)); 13 printf("%d\n", ans); 14 return 0; 15 }
E - Papple Sort
一句话题意:给你一个字符串,要把他变成一个回文最少需要交换字符多少次?如果无法变成回文,输出$-1$。
首先,如果出现奇数次的字符个数大于$1$,则显然无解。
对于相同的字符,咱肯定是要把他们放到左右两边,即配对。
咱可以看出来,交换相同的字符是没有意义的,所以相同字符之间这种相对的位置关系是不会变的。
比如说一个初始为$..a...a...a...a...$的字符串,只看$a$的话,最后如果能形成回文,那么最左边的$a$肯定是与最右边的$a$配对的。
所以咱可以$O(n)$的预处理出与$s_i$配对的字符所在的位置$p_i$。
用树状数组表示某个位置上的字符存在与否,初始时都为$1$。
咱从左往右每次都把$s_i$所对应的字符移到最末尾,再把树状数组上的$p_i-1$表示已经删除。这里说的末尾是不算已配对字符的字符串的末尾。
1 #include<cstdio> 2 #include<cstring> 3 #include<vector> 4 #include<iostream> 5 #include<algorithm> 6 #define pb push_back 7 #define lowbit(x) ((x)&(-(x))) 8 using namespace std; 9 char s[200010]; 10 int n, c[200010], a[200010]; 11 long long ans; 12 vector < int > p[26]; 13 bool check() { 14 int cnt = 0; 15 for (int i = 0; i < 26; ++i) 16 cnt += p[i].size() & 1; 17 return cnt < 2; 18 } 19 void add(int p, int x) { 20 for (; p <= n; p += lowbit(p)) c[p] += x; 21 } 22 int sum(int p) { 23 int res = 0; 24 for (; p; p -= lowbit(p)) res += c[p]; 25 return res; 26 } 27 int main() { 28 scanf("%s", s + 1); 29 n = strlen(s + 1); 30 for (int i = 1; i <= n; ++i) p[s[i]-'a'].pb(i); 31 if (!check()) return puts("-1"), 0; 32 for (int i, sz, x = 0; x < 26; ++x) { 33 for (i = 0; i < (sz = p[x].size()); ++i) 34 a[p[x][i]] = p[x][sz-1-i]; 35 } 36 37 // for (int i = 1; i <= n; ++i) 38 // ans += sum(a[i]), add(a[i], 1); 39 // 上面下面这两种都可以。 40 // for (int i = 1; i <= n; ++i) add(i, 1); 41 // for (int i = 1; i <= n; ++i) { 42 // ans += sum(n) - sum(a[i]); 43 // add(a[i], -1); 44 // } 45 printf("%lld\n", ans / 2); 46 return 0; 47 }