zoukankan      html  css  js  c++  java
  • Ozon Tech Challenge 2020 (Div.1 + Div.2)

    A

    签到

    B

    给你一串有括号组成的字符串,要求你每次删去一个简单括号序列,要求你用最少的次数把字符串里的括号删完(简单括号序列:前n个为‘(’,后n个为’)‘);

    思路:直接贪心字符串里的第一个括号(匹配字符串里的最后一个括号),这样匹配第一次肯定是删掉最长的,同时他删一次后就找不到其他的了

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=4e5+10;
    typedef long long ll;
    int n,m,T,sum,piuy;
    int cnt,resss,cntt;
    string SSSS,ss;
    int ans[maxn],b[maxn],kk[maxn],laa[maxn],poo[maxn];
    bool kop(int a,int b){
        return a>b;
    }
    int read(){
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
        return x*f;
    }
    void ini()
    {
        int pp=0;
        int ppp=0;
        for(int i=1;i<=10;i++)pp++;
        for(int i=10;i<=15;i++) ppp++;
    }
    void run()
    {
        for(int i=0;i<SSSS.size();i++) {
            if(SSSS[i]==')') poo[++cnt]=i+1;
            else laa[++resss]=i+1;
        }
        sort(poo+1,poo+1+cnt,kop);
        sort(laa+1,laa+1+resss);
        int i=1,j=1;
        while(1){
            if(j>resss||cnt<i) break;
            if(laa[i]<poo[j]) {
                kk[++cntt]=laa[i];
                kk[++cntt]=poo[j];
                i++,j++;
                piuy=piuy+2;
            }
            else break;
        }
     
        if(piuy==0)
            puts("0");
        else{
        puts("1");
        cout<<piuy<<endl;
        sort(kk+1,kk+1+cntt);
        for(int i=1;i<=cntt;i++) cout<<kk[i]<<" ";
        puts("");
        }
     
    }
    int main()
    {
        ini();
        cin>>SSSS;
        run();
    }
    

      C

    由抽屉原理可知,当n>mn>m时,必定存在两个aiai模mm同余,此时答案为00

    否则可以直接On2暴力

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=2e5+11;
    typedef long long ll;
    int cnt,resss,cntt;
    string SSSS,ss;
    int ans[maxn],b[maxn],kk[maxn],laa[maxn],poo[maxn];
    ll a[maxn],mod,n;
    int mpp[maxn];
    bool kop(int a,int b){
        return a>b;
    }
    ll read(){
        char c=getchar();ll x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
        return x*f;
    }
    void ini()
    {
        int pp=0;
        int ppp=0;
        for(int i=1;i<=10;i++)pp++;
        for(int i=10;i<=15;i++) ppp++;
    }
    int run()
    {
        n=read(),mod=read();
    //	rep(i,1,n) a[i]=i;//scanf("%lld",&a[i]);
        for(int i=1;i<=n;i++) a[i]=read();
    	for(int i=1;i<=n;i++){
            if(mpp[a[i]%mod]){
                puts("0");
                return 0;
            }
            ++mpp[a[i]%mod];
    	}
    	ll ress=1;
    	for(int i=1;i<=n;++i){
            for(int j=1+i;j<=n;j++){
                ress=ress*(a[i]-a[j])%mod;
            }
    	}
        if(ress<=-1) ress=-ress;
    	cout<<ress<<endl;
     
    }
    int main()
    {
        ini();
        run();
    }
    

      D

    给你一棵树,求出他的根,你可以询问u,v的lca最多n/2次

    可以发现一棵树度数为1的点至少会有一个,因此可以每次挑出两个度数为1的点x,yx,y进行询问,若结果等于其中一个点,则其必定为根。否则删除这两个点并把新出现的度数为1的点加入集合,最坏情况就是恰好询问n2⌊n2⌋次

    #include <bits/stdc++.h>
    using namespace std;
    #define TLE std::ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
    #define ll long long
    #define pb push_back
    typedef pair<int,int> pii;
    const ll mod = 1000000000 ;
    const int INF=0x3f3f3f3f;
    using namespace std;
    const int mxn = 3e5+7 ;
    int n,t,m,k,l,r,res,prime[mxn],isprime[mxn],phi[mxn],dis[mxn],head[mxn];
    string str;
    vector<int>ans[mxn];
    queue<int>q;
    int cnt[mxn];
    bool vis[mxn];
    void del(int x)
    {
        for(auto i : ans[x])
        {
            cnt[i]--;
            if(cnt[i]==1) q.push(i);
        }
    }
    int main()
    {
        TLE;
        scanf("%d",&n);
        for(int i=1,u,v;i<n;i++)
        {
            scanf("%d %d",&u,&v);
            ans[u].pb(v);ans[v].pb(u);
            cnt[u]++;cnt[v]++;
        }
        for(int i=1;i<=n;i++)
            if(cnt[i]==1) q.push(i);
        while(q.size()>=2)
        {
            int u = q.front() ;q.pop();
            int v = q.front() ;q.pop();
            vis[u] = vis[v] = 1 ;
            printf("? %d %d
    ",u,v);
            fflush(stdout);
            cin>>k;
            if(k==u || k==v ) {printf("! %d
    ",k); return 0;}
            del(u);del(v);
        }
        k=0;
        for(int i=1;i<=n;i++)
            if(!vis[i])
                printf("! %d
    ",i) , k++;
    //    assert(k==1);
        return 0 ;
    }
    

      E

    构造的话直接贪心构造。
    123456...,最后补差就行。
    因为从3开始贡献依次为1,1,2,2,3,3,4,4,
    当最后一个的贡献大于我们需要的,也就是我们必须弄出恰好m种,而你继续加的话贡献又会大于m,不加又小于

    我们发现对这个元素x加1,他的贡献就会减一,所以不段++直到满足,后面的直接从1e9补回来

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <vector>
    #include <cmath>
    #include <set>
    #include <map>
    #include <queue>
    #include <iomanip>
    #include <assert.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define pb push_back
    #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 << '
    '; }
      template<typename T, typename...Args>
      void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
      template <template<typename...> class T, typename t, typename... A> 
      void err(const T <t> &arg, const A&... args) {
      for (auto &v : arg) std::cout << v << ' '; err(args...); }
    #else
      #define dbg(...)
    #endif
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 5000 + 5;
     
    int n, m;
     
    void run() {
        cin >> n >> m;
        if(n == 1) {
            if(m == 0) cout << 1 << '
    ';
            else cout << -1 << '
    ';   
            return;
        }
        vector <int> a;
        a.push_back(1);
        a.push_back(2);
        int now = 1, cnt = 0;
        int t = 0, p = 3;
        while(t < m) {
            if(t + now > m) {
                int r = m - t;
                --p;
                for(int i = p + 1;; i++) {
                    int L = i - p, R = p;
                    if((R - L + 1) / 2 == r) {
                        a.push_back(i);
                        t += r;
                        break;
                    }
                }
            } else {
                a.push_back(p++);
                t += now;
                if(++cnt == 2) {
                    ++now, cnt = 0;   
                }
            }
        }
        if(sz(a) > n) {
            cout << -1 << '
    ';
            return;   
        }
        int s = 1e9;
        while(sz(a) < n) {
            a.push_back(s);
            s -= 50000;   
        }
        sort(all(a));
        for(auto it : a) cout << it << ' ';
    }
     
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        run();
        return 0;
    }
    

      F

    你有n个数, 你可以进行让某个数加一或减一的操作, 求最少的操作次数让这些数最大公因数不为1

    思路,我们先假设gcd最少为2时候,那么最多操作只有n次对吧,因为gcd=2说明全是偶数,序列全是奇数我们只需每个位置操作1次,总共就n次。

    在最多操作只有n次的条件下,那么一个位置操作数>=2的数量就是<=n/2,反过来说一个位置操作数小于等于1的位置个数就是大于等于n/2,那么也就是我们随机选择一个位置他操作个数小于等于1的几率起码是1/2,那么随机抽取20次,抽到操作个数大于等于2的就得是1/(2^20),忽略不计,所以枚举20次必定找到一个操作数小于等于1的

    ,那么找到这个数字后对他操作就是三个,-1,0,+1,三种情况分别判断一下,看哪个操作是最好次数就行

    然后就行对这个数字的质因数进行判断看哪个质因数是最优的,因为所有数字的gcd,就是他们公共质因数

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <map>
    #include <algorithm>
    #define ll long long
    using namespace std;
    
    template <typename T>
    void read(T &x) {
        x = 0; bool f = 0;
        char c = getchar();
        for (;!isdigit(c);c=getchar()) if (c=='-') f=1;
        for (;isdigit(c);c=getchar()) x=x*10+(c^48);
        if (f) x=-x;
    }
    
    template <typename T>
    void write(T x) {
        if (x < 0) putchar('-'), x = -x;
        if (x >= 10) write(x / 10);
        putchar('0' + x % 10);
    }
    
    const int N = 205000;
    ll a[N], ans, n;
    map<ll, int> mp;
    void check(ll k) {
        ll res = 0; if (mp[k]) return; mp[k] = 1;
        for (int i = 1;i <= n; i++) {
            if (a[i] >= k) res += min(a[i] % k, k - a[i] % k);
            else res += k - a[i];
            if (res >= ans) return;
        }
        ans = min(ans, res);
    }
    
    void work(ll x) {
        for (ll i = 2;i * i <= x; i++) {
            if (x % i) continue;
            while (x % i == 0) x /= i;
            check(i);
        }
        if (x > 1) check(x);
    }
    
    #include <cstdlib>
    #include <ctime>
    int main() {
    //    freopen ("hs.in","r",stdin);
    //  srand(time(0));
        read(n); ans = n;
        for (int i = 1;i <= n; i++) read(a[i]);
        random_shuffle(a + 1, a + n + 1);
        int lim = min(n, 300ll);
        for (int i = 1;i <= lim; i++) {
            ll x = a[i];
            work(x), work(x + 1); if (x > 1) work(x - 1);
        }
        cout << ans << endl;
        return 0;
    }
    

      

  • 相关阅读:
    【poj3294】 Life Forms
    【poj3415】 Common Substrings
    【poj3693】 Maximum repetition substring
    【bzoj2034】 2009国家集训队—最大收益
    【bzoj4198】 Noi2015—荷马史诗
    【poj2406】 Power Strings
    【ural1297】 Palindrome
    【spoj SUBST1】 New Distinct Substrings
    【poj1743】 Musical Theme
    django rest framework serializers小结
  • 原文地址:https://www.cnblogs.com/hgangang/p/12411709.html
Copyright © 2011-2022 走看看