Educational Codeforces Round 81 (Rated for Div. 2)
A~D→:https://www.cnblogs.com/GoodVv/p/12249839.html
因为懒所以 A ~ D 拿给VV写了 ʅ(‾◡◝)ʃ
但是我的代码还是会放上的(思路可能和VV博客里写的不一样)
#include<bits/stdc++.h> using namespace std; int main() { int t; cin >> t; while(t --) { int n ; cin >> n; if(n & 1) cout << 7 , n -= 3; for(int i = 1 ; i <= n / 2 ; i ++) cout << 1; cout << '\n'; } return 0; }
#include<bits/stdc++.h> using namespace std; #define ll long long map<ll , ll>cnt; ll n , x , ans , sum; string s; int main() { ll t; cin >> t; while(t --) { cnt.clear(); ans = sum = 0; cin >> n >> x >> s; if(x == 0) ans = 1; for(auto i : s) { if(i - '0') sum --; else sum ++; cnt[sum] ++; } if(!sum) { if(!cnt[x]) cout << 0 << '\n'; else cout << -1 << '\n'; continue ; } for(auto it : cnt) if(abs(it.first - x) % (sum) == 0) { if((x > it.first && sum < 0) || (x < it.first && sum > 0)) continue; ans += it.second; } cout << ans << '\n'; } return 0; }
#include<bits/stdc++.h> using namespace std; #define inf 0x3f3f3f3f const int N = 1e5 + 10; int pos[N][27]; char s[N] , t[N]; int main() { int T; cin >> T; while(T --) { cin >> s + 1 >> t + 1; int len1 = strlen(s + 1) , len2 = strlen(t + 1); for(int j = 0 ; j < 26 ; j ++) pos[len1][j] = inf; for(int i = len1 - 1; i >= 0 ; i --) { for(int j = 0 ; j < 26 ; j ++) pos[i][j] = pos[i + 1][j]; pos[i][s[i + 1] - 'a'] = i + 1; } int now = 1 , flag = 1 , ans = 0; while(now <= len2) { if(pos[0][t[now] - 'a'] == inf) { flag = 0 ; break ; } int idx = pos[0][t[now] - 'a']; while(idx != inf && now <= len2) now ++ , idx = pos[idx][t[now] - 'a']; ans ++ ; } if(!flag) cout << -1 << '\n'; else cout << ans << '\n'; } return 0; }
#include<bits/stdc++.h> #define ll long long using namespace std; const int N = 2e5 + 10; ll eular(ll n) { ll ans = n; for(ll i = 2; i * i <= n ; i ++) { if(n % i == 0) { ans = ans / i * (i - 1); while(n % i == 0) n /= i; } } if(n > 1) ans = ans / n * (n - 1); return ans; } int main() { int t; cin >> t; while(t --) { ll a , b; cin >> a >> b; ll gcdd = __gcd(a , b); b /= gcdd; cout << eular(b) << '\n'; } return 0; }
E. Permutation Separation
题目链接:https://codeforces.com/contest/1295/problem/E
题意:
给你一个长度为n的数组,其中 1 ~ n 每个数恰好在该数组中出现一次,并且每个数都有自己的价值 ai
你要在数组中任意位置切一刀使数组划分为左集合和右集合(刚切完左右集合不得为空)
切完后你可以将一个集合的任意一个元素 x 丢到另一个集合去,但是你需要支付 a[x]的代价
现要使操作结束后右集合的元素均大于左集合的元素(或其中任意一集合为空集),问你最小代价是多少
分析:
先模拟一遍
假设 n = 6,数组的元素分别为 3,6,5,4,1,2 ,那么我们可以切的位置分别有3,6、6,5、5,4、4,1、1,2之间
我们将每一个可以切的间隙从左往右进行编号,并定义为切点,如图所示:
其中 1 左边的切点有①②③④,右边的切点有⑤
2 左边的切点有①②③④⑤,右边没有切点
3 左边没有切点,右边的切点有①②③④⑤
......
在开始之前,我们还要知道当我们操作完之后,左集合要么为空,要么剩余 m 个元素,而剩余的元素分别是1 ~ m
好了在了解完以上后,我们采用边枚举边更新的方法
首先,让我们用pos[i] 表示第 i 个元素的位置,其中pos[1] = 5,pos[2] = 6,pos[3] = 1...
用sum[i] 表示前 i 个位置的代价前缀和,其意义是将切点 i 左边的数全移至右边所付出的代价
初始我们先让第 i 个切点的代价为sum[i] , 即在切完之后将左边所有数都移至右集合。
我们用线段树维护每个切点的花费(第 i 个位置(区间)维护第 i 个切点),然后我们开始对每个元素进行枚举
one首先是元素 1 , pos[1] = 5 , 我们观察第五个元素右边的切点有⑤ , 左边的切点有①②③④
对于右边的切点⑤:它当前的花费为sum[5] ,包括了元素1的代价,但实际上在切完⑤之后元素1在左集合,且我们并不需要把元素1移至右边,所以我们把切点⑤的花费减去元素1的代价
对于左边的切点:在切完之后元素1是处于集合的右边,所以开始的时候sum[1],sum[2],sum[3],sum[4]并没有算上元素1右移的代价
而实际上元素1应该要移至左集合,所以我们把切点①~④的花费加上元素1的代价
two然后是元素2, pos[2] = 6 , 第六个元素右边没有切点,左边的切点有①②③④⑤
对于右边的切点:无。
对于左边的切点:切完之后元素2是处于集合的右边,所以开始的时候sum[1],sum[2],sum[3],sum[4],sum[5]并没算上元素2右移的代价
而实际上元素2应该要移至左集合,所以我们把切点①~⑤的花费加上元素2的代价
three紧接着是元素3,pos[3] = 1,第一个元素的左边没有切点,右边的切点有①②③④⑤
对于右边的切点:在切完之后元素3是处于集合的左边,且我们并不需要把元素3右移。
但在初始的时候我们统一把左集合的全都右移了,所以初始的时候切点①②③④⑤的花费都算上元素3的代价,所以我们要把他们的花费减去元素3的代价
对于左边的切点:无。
......
根据以上我们发现,对于第 i 次枚举(元素 i )编号为 1 ~ pos[i] - 1 的切点(元素 i 的右边)花费都要减去 i 的代价,而编号 pos[i] ~ n - 1的切点(元素i的左边)花费都要加上 i 的代价
这只要用线段树区间更新一波就可以把复杂度降至 logn,在加上枚举的时间消耗,总复杂度为 nlogn . 完全OK
ans 的值我们在每次枚举完更新
代码:
#include<bits/stdc++.h> using namespace std; #define ll long long const int N = 2e5 + 10; struct Segment_Tree{ ll l , r; ll minn , lazy; }tree[N << 2]; void build(ll l , ll r , ll rt , ll *aa) { tree[rt].l = l , tree[rt].r = r; if(l == r) { tree[rt].minn = aa[l]; return ; } ll mid = l + r >> 1; build(l , mid , rt << 1 , aa); build(mid + 1 , r , rt << 1 | 1 , aa); tree[rt].minn = min(tree[rt << 1].minn , tree[rt << 1 | 1].minn); } void push_down(ll rt) { if(tree[rt].lazy) { tree[rt].minn += tree[rt].lazy; tree[rt << 1].minn += tree[rt].lazy; tree[rt << 1 | 1].minn += tree[rt].lazy; tree[rt << 1].lazy += tree[rt].lazy; tree[rt << 1 | 1].lazy += tree[rt].lazy; tree[rt].lazy = 0; } } void update_range(ll L , ll R , ll val , ll rt) { if(tree[rt].r < L || tree[rt].l > R) return ; if(L <= tree[rt].l && R >= tree[rt].r) { tree[rt].lazy += val; tree[rt].minn += val; return ; } push_down(rt); ll mid = tree[rt].l + tree[rt].r >> 1; if(L <= mid) update_range(L , R , val , rt << 1); if(R > mid) update_range(L , R , val , rt << 1 | 1); tree[rt].minn = min(tree[rt << 1].minn , tree[rt << 1 | 1].minn); } ll query_min(ll L , ll R , ll rt) { if(L <= tree[rt].l && R >= tree[rt].r) return tree[rt].minn; push_down(rt); ll mid = tree[rt].l + tree[rt].r >> 1; ll res1 = (0x3f3f3f3f3f3f3f3fll) , res2 = (0x3f3f3f3f3f3f3f3fll); if(L <= mid) res1 = query_min(L , R , rt << 1); if(R > mid) res2 = query_min(L , R , rt << 1 | 1); return min(res1 , res2); } ll a[N] , pos[N] , sum[N]; int main() { int n ; cin >> n; for(int i = 1 ; i <= n ; i ++) { int x ; cin >> x; pos[x] = i; } for(int i = 1 ; i <= n ; i ++) cin >> a[i] , sum[i] = sum[i - 1] + a[i]; build(1 , n - 1 , 1 , sum); ll ans = min(a[1] , a[n]); for(int i = 1 ; i <= n - 1 ; i ++) { update_range(pos[i] , n - 1 , -a[pos[i]] , 1); update_range(1 , pos[i] - 1 , a[pos[i]] , 1); ans = min(ans , query_min(1 , n - 1 , 1)); } update_range(pos[1] , n - 1 , -a[pos[1]] , 1); update_range(1 , pos[i] - 1 , a[pos[1]] , 1); cout << ans << '\n'; return 0; }