Codeforces Round #694 (Div. 1) 部分简要题解

A - Strange Birthday Party

k越大的人应该获得更小价值的礼物。

证明:有两个人A,B,其中k_A>k_B,有两个礼物价值分别是a,b,其中a>b。当A,B分别获得礼物a,b,付出的代价是a+b。当A,B分别获得礼物b,a,付出的代价是b+min(a,c_{k_B})

#include<bits/stdc++.h>
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
using namespace std ;
int main()
{
    ios ;
    int T ;
    cin >> T ;
    while(T --)
    {
        int n , m ;
        cin >> n >> m ;
        vector<int> k(n) ;
        vector<int> c(m + 1) ;
        for(int i = 0 ; i < n ; i ++)  cin >> k[i] ;
        for(int i = 1 ; i <= m ; i ++)  cin >> c[i] ;
        sort(k.begin() , k.end()) ;
        long long ans = 0 ;
        int now = 1 ;
        for(int i = n - 1 ; i >= 0 ; i --)
        {
            if(now <= k[i])
            {
                ans += c[now] ;
                now ++ ;
            }
            else
            {
                ans += c[k[i]] ;
            }
        }
        cout << ans << '\n' ;
    }
    return 0 ;
}

B - Strange Definition

\frac{lcm(x,y)}{gcd(x,y)}是平方数等价于x*y是平方数。

[1,1000000]内每个数的偶数个数的因子都去除掉,去除后的相同的数认为是一类。

在一秒后,类的大小是偶数的类,全是1的类可以合并。

#include<bits/stdc++.h>
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
using namespace std ;
int main()
{
    ios ;
    int T ;
    vector<int> id(1000001 , 0) ;
    function<void()> init = [&]()
    {
        for(int i = 1 ; i <= 1000000 ; i ++)  id[i] = i ;
        for(int i = 2 ; i <= 1000000 ; i ++)
        {
            for(int j = i ; j <= 1000000 ; j += i)
            {
                int cnt = 0 ;
                while(id[j] % i == 0)
                {
                    id[j] /= i ;
                    cnt ++ ;
                }
                if(cnt % 2 == 1)  id[j] *= i ;
            }
        }
    } ;
    cin >> T ;
    init() ;
    while(T --)
    {
        int n , q ;
        cin >> n ;
        vector<int> v(n) ;
        for(int i = 0 ; i < n ; i ++)
        {
            int x ;
            cin >> x ;
            v[i] = id[x] ;
        }
        int ans = 0 ;
        int ans2 = 0 ;
        sort(v.begin() , v.end()) ;
        for(int i = 0 ; i < n ; i ++)
        {
            int j = i ;
            while(j + 1 < n && v[j + 1] == v[j])  j ++ ;
            if((j - i + 1) % 2 == 0 || v[i] == 1)  ans2 += j - i + 1 ;
            ans = max(ans , j - i + 1) ;
            i = j ;
        }
        cin >> q ;
        while(q --)  
        {
            long long w ;
            cin >> w ;
            if(w >= 1)  cout << max(ans , ans2) << '\n' ;
            else  cout << ans << '\n' ;
        }
    }
    return 0 ;
}

C - Strange Shuffle

这道题目有一些抽象,主要是考察打表能力。

打表之后会发现,每次迭代会增加一个大于k的数。并且这些大于k的数是连续的。先花费\sqrt{n}的次数产生一个\sqrt{n}的连续大于k的段,再花费\sqrt{n}的次数找到一个大于k的数。

然后发现a[p-1]<a[p]<a[p+1],并且递增的长度为3的段只有一个,通过三分找到这个段。

#include<bits/stdc++.h>
using namespace std ;
int n , k ;
int ask(int x)
{
    if(x > n)  x -= n ;
    printf("? %d\n" , x) ;
    fflush(stdout) ;
    int ans ;
    scanf("%d" , &ans) ;
    return ans ;
}
int main()
{
    cin >> n >> k ;
    int block = (int)(sqrt(n)) - 1 ;
    for(int i = 1 ; i <= block ; i ++)  ask(1) ;
    int now = 1 ;
    int l , r ;
    for(int i = 1 ; i <= n ; i ++)
    {
        if(ask(now) > k)
        {
            l = now ;
            r = now + n - 1 ;
            break ;
        }
        else  now += block ;
        if(now > n)  now -= n ;
    }
    int ans = l ;
    while(l <= r)
    {
        int lmid = (2 * l + r) / 3 ;
        int rmid = (2 * r + l + 2) / 3 ;
        if(ask(lmid) < ask(rmid))  ans = lmid , r = rmid - 1 ;
        else  ans = rmid , l = lmid + 1 ;
    }
    ans ++ ;
    if(ans > n)  ans -= n ;
    printf("! %d\n" , ans) ;
    return 0 ;
}

D - Strange Housing

好吧,比赛时候就算写了这题,也会因为一个细节fst。因为有TLE36

很容易发现如果是个连通图,肯定是YESbfs的时候能涂色就涂色即可。如果不是个连通图,就是NO

#include<bits/stdc++.h>
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
using namespace std ;
int main()
{
    ios ;
    int T ;
    cin >> T ;
    while(T --)
    {
        int n , m ;
        cin >> n >> m ;
        vector<vector<int>> g(n + 1) ;
        for(int i = 1 ; i <= m ; i ++)
        {
            int u , v ;
            cin >> u >> v ;
            g[u].push_back(v) ;
            g[v].push_back(u) ;
        }
        function<bool()> can = [&]()
        {
            queue<int> q ;
            q.push(1) ;
            vector<bool> vis(n + 1 , false) ;
            vis[1] = true ;
            while(!q.empty())
            {
                int u = q.front() ;
                q.pop() ;
                for(auto v : g[u])  if(!vis[v])  vis[v] = true , q.push(v) ;
            }
            for(int i = 1 ; i <= n ; i ++)  if(!vis[i])  return false ;
            return true ;
        } ;
        if(!can())
        {
            cout << "NO\n" ;
            continue ;
        }
        vector<int> c(n + 1 , -1) ;
        function<void()> bfs = [&]()
        {
            queue<int> q ;
            q.push(1) ;
            c[1] = 1 ;
            while(!q.empty())
            {
                int u = q.front() ;
                q.pop() ;
                bool flag = 0 ;
                for(auto v : g[u])  if(c[v] == 1)  flag = 1 ;
                if(flag)  c[u] = 0 ;
                else  c[u] = 1 ;
                for(auto v : g[u])  if(c[v] == -1)  q.push(v) , c[v] = 0 ;
            }
        } ;
        bfs() ;
        cout << "YES\n" ;
        int cnt = 0 ;
        for(int i = 1 ; i <= n ; i ++)  if(c[i] == 1)  cnt ++ ; 
        cout << cnt << '\n' ;
        for(int i = 1 ; i <= n ; i ++)  if(c[i] == 1)  cout << i << ' ' ;
        cout << '\n' ;
    }
    return 0 ;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值