Educational Codeforces Round 81 (Rated for Div. 2)

传送门

A. Display The Number

签到。

Code
/*
 * Author:  heyuhhh
 * Created Time:  2020/1/29 22:37:40
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << '\n'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
  #define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;
 
void run(){
    int n; cin >> n;
    if(n % 2 == 0) {
        for(int i = 1; i <= n / 2; i++) cout << 1;
        cout << '\n';
    } else {
        cout << 7;
        n -= 3;
        for(int i = 1; i <= n / 2; i++) cout << 1;
        cout << '\n';
    }
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    int T; cin >> T;
    while(T--) run();
    return 0;
}

B. Infinite Prefixes

题意:
给出一个01串\(s\),现在定义\(t\)串为\(s\)串的无穷拼接,\(s\)串的长度\(n\)满足\(n\leq 10^5\)
给出\(x,-10^9<x<10^9\),问\(t\)串有多少个前缀,满足\(0\)的个数比\(1\)的个数多\(x\)

思路:
将题目要求转化为式子即为:

\[x\cdot pre_n+y=x,x\geq 0,min_{pre}\leq y\leq max_{pre} \]

这里的\(x\)就相当于枚举多少个整的\(s\)串,而最后加上的\(y\)则有限制。
因为串长为\(10^5\),故预处理出\(pre_i\)后直接枚举\(Min\)~\(Max\)即可,若最终的\(x\geq 0\)则说明存在解。
当然还需要考虑一些细节,比如模\(0\)的情况。
细节见代码:

Code
/*
 * Author:  heyuhhh
 * Created Time:  2020/1/29 22:45:58
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << '\n'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
  #define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;
 
int n, x;
char s[N];
int pre[N];
 
void run(){
    cin >> n >> x;
    cin >> (s + 1);
    map <int, int> mp;
    int Max = -INF, Min = INF;
    for(int i = 1; i <= n; i++) {
        pre[i] = pre[i - 1];
        if(s[i] == '0') ++pre[i];
        else --pre[i];  
        mp[pre[i]]++; 
        Max = max(Max, pre[i]);
        Min = min(Min, pre[i]);
    }
    if(pre[n] == 0) {
        int ans;
        if(x >= Min && x <= Max) ans = -1;
        else if(x == 0) ans = 1;
        else ans = 0;
        cout << ans << '\n';
        return;   
    }
    int ans = 0;
    for(int i = Min; i <= Max; i++) {
        int t = x - i;
        if(t % pre[n] == 0 && t / pre[n] >= 0) {
            ans += mp[i];
        }
    }
    if(x == 0) ++ans;
    cout << ans << '\n';
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    int T; cin >> T;
    while(T--) run();
    return 0;
}

C. Obtain The String

贪心即可。
预处理出\(s\)串的序列自动机即可。

Code
/*
 * Author:  heyuhhh
 * Created Time:  2020/1/29 23:04:19
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << '\n'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
  #define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;
 
int n, m;
char s[N], t[N];
int nxt[N][26];
 
void run(){
    cin >> (s + 1) >> (t + 1);
    n = strlen(s + 1), m = strlen(t + 1);
    for(int i = 0; i < 26; i++) nxt[n][i] = 0;
    for(int i = n - 1; i >= 0; i--) {
        for(int j = 0; j < 26; j++) {
            if(s[i + 1] != 'a' + j) nxt[i][j] = nxt[i + 1][j];
            else nxt[i][j] = i + 1;
        }  
    }
    int ans = 1, now = 0;
    for(int i = 1; i <= m; i++) {
        while(1) {
            int to = nxt[now][t[i] - 'a'];
            if(now == 0 && to == 0) {
                cout << -1 << '\n';
                return;   
            }
            now = to;
            if(now != 0) break;
            else ++ans;
        }
    }
    cout << ans << '\n';
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    int T; cin >> T;
    while(T--) run();
    return 0;
}

D. Same GCDs

题意:
给出\(a,m,1\leq a<m\leq 10^{10}\),现在求有多少个\(x\),满足\(0\leq x<m\)\(gcd(a,m)=gcd(a+x,m)\)

思路:
\(\displaystyle gcd(a,m)=d\),那么有\(\displaystyle a=k_1d,m=k_2d,gcd(k_1,k_2)=1\)
因为\(\displaystyle gcd(a+x,m)=d\),那么可令\(\displaystyle x=k_3d\),则有:

\[gcd(k_1+k_3,k_2)=1 \]

其中\(\displaystyle 0\leq k_3<k2\)

那么现在就是要求\([k_1,k_1+k_2)\)中与\(k_2\)互质的数,我们对\(k_2\)分解质因子,假设其质因子为\(p_1,p_2,\cdots,p_t\)
那么根据欧拉函数的思想来容斥,则有:

\[f(i)=i\prod_{i=1}^t(1-\frac{1}{p_i}) \]

答案即为:

\[f(k_1+k_2-1)-f(k_1-1) \]

观察到后面质因子部分都是相同的,那么上式可化为:

\[k_2\prod_{i=1}^t(1-\frac{1}{p_i})=\varphi(k_2) \]

比赛时容斥我是直接暴力来容斥的,代码如下:

Code
/*
 * Author:  heyuhhh
 * Created Time:  2020/1/29 23:40:43
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << '\n'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
  #define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;
 
ll a, m;
 
ll get(ll n, ll p) {
    return n / p;
}
 
ll get(ll l, ll r, ll p) {
    return get(r, p) - get(l - 1, p);   
}
 
vector <ll> divs;
ll ans, l, r;
 
void solve(int cur, ll now, int cnt) {
    if(now > r) return;
    if(cur == sz(divs)) {
        if(now == 1) return;
        if(cnt & 1) ans -= get(l, r, now);
        else ans += get(l, r, now);
        return;
    }  
    solve(cur + 1, now, cnt);
    solve(cur + 1, now * divs[cur], cnt ^ 1);
}
 
void run(){
    divs.clear();
    cin >> a >> m;
    ll d = __gcd(a, m);
    a /= d, m /= d;
    l = a, r = a + m - 1;
    ans = m;
    for(ll i = 2; i * i <= m; i++) {
        if(m % i == 0) {
            divs.push_back(i);
            while(m % i == 0) m /= i;
        }
    }
    if(m > 1) divs.push_back(m);
    solve(0, 1, 0);
    cout << ans << '\n';
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    int T; cin >> T;
    while(T--) run();
    return 0;
}

E. Permutation Separation

题意:
给出一个\(1\)\(n\)的排列,每个数有其代价\(a_i\)
现在要给出一种划分将排列划分为\(p_1,\cdots,p_k\)\(p_{k+1},\cdots,p_n\)两部分。
然后可以移动左边部分的数到右边,同理右边也可以移到左边,需要对应的花费。
现在问使得左边部分的每一个数都小于右边部分的每一个数的最小花费是多少,划分自己定。

思路:
考虑终态,类似于\(1,2,\cdots,i\)\(i+1,i+2,\cdots,n\)两部分。
接下来考虑每个数对划分的贡献,若\(i\)在左边部分,那么对于所有\(1\) ~ \(pos_i-1\)的划分都会有贡献;若\(i\)在右边部分,那么对于所有\(pos_i\) ~ \(n\)的划分都会有贡献。
因为终态的变化是连续的,每次只有一个数从右半部分到左半部分,而一个数对划分的贡献是区间形式。所以直接枚举终态,用线段树维护贡献,最终对于每一个终态查询最小花费的划分即可。
实现时记得\(long\ long\),细节见代码:

Code
/*
 * Author:  heyuhhh
 * Created Time:  2020/1/30 11:39:25
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << '\n'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
  #define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 2e5 + 5;

int n;
int p[N], a[N], b[N];

ll minv[N << 2], lz[N << 2];

void tag(int o, ll v) {
    minv[o] += v;
    lz[o] += v;   
}

void push_down(int o) {
    if(lz[o] != 0) {
        tag(o << 1, lz[o]);
        tag(o << 1|1, lz[o]);
        lz[o] = 0;
    }   
}

void push_up(int o) {
    minv[o] = min(minv[o << 1], minv[o << 1|1]);
}

void update(int o, int l, int r, int L, int R, int v) {
    if(L <= l && r <= R) {
        tag(o, v);
        return;
    }
    push_down(o);
    int mid = (l + r) >> 1;
    if(L <= mid) update(o << 1, l, mid, L, R, v);
    if(R > mid) update(o << 1|1, mid + 1, r, L, R, v);
    push_up(o);
}

void run(){
    for(int i = 1; i <= n; i++) {
        cin >> b[i]; p[b[i]] = i;   
    }
    for(int i = 1; i <= n; i++) {
        cin >> a[b[i]];
    }
    for(int i = 1; i <= n; i++) {
        if(p[i] < n) update(1, 1, n - 1, p[i], n - 1, a[i]);   
    }
    ll ans = minv[1];
    for(int i = 1; i <= n; i++) {
        if(p[i] < n) update(1, 1, n - 1, p[i], n - 1, -a[i]);
        if(p[i] > 1) update(1, 1, n - 1, 1, p[i] - 1, a[i]);
        ans = min(ans, minv[1]);
    }
    cout << ans << '\n';
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    while(cin >> n) run();
    return 0;
}
posted @ 2020-01-30 18:43  heyuhhh  阅读(195)  评论(0编辑  收藏  举报