zoukankan      html  css  js  c++  java
  • Codeforces 817+818(A~C)

    (点击题目即可查看原题)

    817A Treasure Hunt

    题意:给出起点和终点,每次移动只能从 (a,b)移动至(a+x,b+y) , (a+x,b-y) , (a-x,b+y) , (a-x,b-y) 四个位置,问能否从终点走到起点

    思路:先计算出起点和终点的横纵坐标之差 X,Y, 首先必须满足 X%x == 0 && Y % y == 0 ,这样才可以走到和终点一样的位置,后计算 X/x . Y/y ,我们注意到如果 X/x != Y/y 那么就可能无法用到达,不过,我们可以在两次运动过程中只走X方向或者Y方向,也就是如果 abs( X/x - Y/y ) % 2 == 0 ,那么也是可以到达的;此外的情况都是无法到达的。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    #include<string>
    #include<fstream>
    #include<vector>
    #include<stack>
    #include <map>
    #include <iomanip>
    #define bug cout << "**********" << endl
    #define show(x,y) cout<<"["<<x<<","<<y<<"] "
    //#define LOCAL = 1;
    using namespace std;
    typedef long long ll;
    const int inf = 0x3f3f3f3f;
    const ll mod = 1e6 + 3;
    const int Max = 1e5 + 10;
    
    int s_x, s_y, e_x, e_y;
    int x, y;
    
    int main()
    {
    #ifdef LOCAL
        freopen("input.txt", "r", stdin);
        freopen("output.txt", "w", stdout);
    #endif
        while (scanf("%d%d%d%d", &s_x, &s_y, &e_x, &e_y) != EOF)
        {
            scanf("%d%d", &x, &y);
            if (abs(s_x - e_x) % x == 0 && abs(s_y - e_y) % y == 0
             && abs(abs(s_x - e_x) / x - abs(s_y - e_y) / y) % 2 == 0)
            {
                printf("YES
    ");
            }
            else
            {
                printf("NO
    ");
            }
        }
        return 0;
    }
    817A

     817B Makes And The Product 

    题意:给出n个数a[1] ~ a[n] ,求使得 a[i] * a[j] * a[k] 最小的组合 (i,j,k) 有多少个,其中 i , j , k 互不相等。

    思路:摆明了让你求最小的三个值的个数,求出最小值,,次小值的,,第三小值的个数,然后根据以下规律凑成组合并输出个数,emmm,组合数

    1)最小的有三个以上,那么三个均有最小的组成

    2)如果最小的只有两个,那么最小的肯定要选,所以由两个最小和一个次小组成

    3)最小的只有一个,次小的有两个以上,那么由一个最小和两个次小组成

    4)最小和次小都只有一个,那么由最小,次小,第三小各选一个组成

    输出对应的组合数即可(博主用自己的组合数板子写了第一发,结果范围不够,WA了,不过这个地方不需要用组合数板子来写,因为计算次数最多4次,直接算就好)

    #include<iostream>
    #include<cstdio>
    #include<stdio.h>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    #include<string>
    #include<fstream>
    #include<vector>
    #include<stack>
    #include <map>
    #include <iomanip>
    #define bug cout << "**********" << endl
    #define show(x,y) cout<<"["<<x<<","<<y<<"] "
    //#define LOCAL = 1;
    using namespace std;
    typedef long long ll;
    const int inf = 0x3f3f3f3f;
    const ll mod = 1e9 + 7;
    const int Max = 1e5 + 10;
    
    int n;
    int a[Max];
    map<int, int>mp;    //记录每个数字出现的次数
    
    
    int main()
    {
    #ifdef LOCAL
        freopen("input.txt", "r", stdin);
        freopen("output.txt", "w", stdout);
    #endif
        while (scanf("%d", &n) != EOF)
        {
            mp.clear();
            for (int i = 1;i <= n;i++)
            {
                scanf("%d", a + i), mp[a[i]]++;
            }
    
            sort(a + 1, a + 1 + n);
            int tot = unique(a + 1, a + 1 + n) - a - 1; //排序并去重,使得a[1]~a[3]对应最小的三个数
    
            if (mp[a[1]] >= 3)                                    //最小的有三个以上,那么三个均有最小的组成
            {
                printf("%d
    ",mp[a[1]] * (mp[a[1]] -1 ) * (mp[a[1]] -2) / 6);
            }
            else if (mp[a[1]] == 2)                               //如果最小的只有两个,那么最小的肯定要选,所有由两个最小和一个次小组成
            {
                printf("%d
    ", mp[a[2]]);
            }
            else if (mp[a[1]] == 1 && mp[a[2]] >= 2)              //最小的只有一个,次小的有两个以上,那么有一个最小和两个次小组成
            {
                printf("%d
    ", mp[a[2]] * (mp[a[2]]  - 1) / 2);
            }
            else                                                  //最小和次小都只有一个,那么最小,次小,第三小各选一个
            {
                printf("%d
    ",mp[a[3]]);
            }
        }
    
        return 0;
    }
    817B

    817C Really Big Numbers

    题意:给出两个数n,s,问在 [1,n] 范围内有多少个数  满足 x 和 x 的各个位上的数之和 大于s ( x 属于 [1,n])

    思路:打表找规律,发现从某一个数开始,后面的数都是满足条件的,那么就简单了,二分第一个满足的数,其后的数就都满足条件了

    #include<iostream>
    #include<cstdio>
    #include<stdio.h>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    #include<string>
    #include<fstream>
    #include<vector>
    #include<stack>
    #include <map>
    #include <iomanip>
    
    #define bug cout << "**********" << endl
    #define show(x, y) cout<<"["<<x<<","<<y<<"] "
    #define LOCAL = 1;
    using namespace std;
    typedef long long ll;
    const int inf = 0x3f3f3f3f;
    const ll mod = 1e9 + 7;
    const int Max = 1e5 + 10;
    
    ll n, m;
    
    int main()
    {
    #ifdef LOCAL
        //freopen("input.txt", "r", stdin);
        //freopen("output.txt", "w", stdout);
    #endif
        while (scanf("%lld%lld", &n, &m) != EOF)
        {
            ll l = 1, r = n;
            while (l <= r)
            {
                ll sum = 0;
                ll mid = (l + r) >> 1;
                ll k = mid;
                while (k)
                {
                    sum += k % 10;
                    k /= 10;
                }
                if (abs(mid - sum) < m)
                {
                    l = mid + 1;
                }
                else
                {
                    r = mid - 1;
                }
            }
            printf("%lld
    ", n - l + 1);
        }
        return 0;
    }
    817C

    818A Diplomas and Certificates 

    题意:有n个人,需要为他们分两种奖品,其中一种奖品的数量必须是另一种奖品数量的k倍,每个人只能分到一个奖品,并且有奖品的人数不得超过n/2个,输出两种奖品的数量和没有得奖的人数

    思路:一个简单的公式 x + k * x <= n/2 ,得到的x向下取整,输出 x , k * x , n - (k+1)*x 就OK了。

    #include<iostream>
    #include<cstdio>
    #include<stdio.h>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    #include<string>
    #include<fstream>
    #include<vector>
    #include<stack>
    #include <map>
    #include <iomanip>
    #define bug cout << "**********" << endl
    #define show(x,y) cout<<"["<<x<<","<<y<<"] "
    //#define LOCAL = 1;
    using namespace std;
    typedef long long ll;
    const int inf = 0x3f3f3f3f;
    const ll mod = 1e9 + 7;
    const int Max = 1e5 + 10;
    
    ll n, k;
    
    int main()
    {
    #ifdef LOCAL
        freopen("input.txt", "r", stdin);
        freopen("output.txt", "w", stdout);
    #endif
        while (scanf("%lld%lld", &n, &k) != EOF)
        {
            ll x = (n/2) / (k + 1);
            printf("%lld %lld %lld
    ", x, k*x, n - (k + 1)*x);
        }
        return 0;
    }
    818A

    818B Permutation Game 

    题意:有n个人围成环玩游戏,每个人的位置按顺时针从1~n排列,一共m轮,每轮选出一个领导者,用l[i]表示第i轮的领导是谁,每个人当领导的时候,他会选择他后面第a[i]个人担任下一轮的领导,并且a[i] 只能是 1 ~ n 中的值,并且每个人的a[i]  都不一样,换句话说,n个人的a[i]组成 1 ~ n ,给出了n,m, l[i],求a[i],如果不存在,输出-1

    思路:我们注意到,每一轮的领导者都是上一轮领导后的第a[i]位,那么 a[i-1] = l[i] - l[i-1] ,又因为n个人排成环,所以当 l[i] < l[i-1] 的时候,a[i-1] = l[i] + n - l[i-1],这样就可以求出a[i]了,对于不确定的a[i],我们给其一个没有出现过的数当成这个数的a[i]即可。而如果某两个人的a[i]相同,那么就不存在,输出-1

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    #include<string>
    #include<fstream>
    #include<vector>
    #include<stack>
    #include <map>
    #include <iomanip>
    
    #define bug cout << "**********" << endl
    #define show(x, y) cout<<"["<<x<<","<<y<<"] "
    #define LOCAL = 1;
    using namespace std;
    typedef long long ll;
    const int inf = 0x3f3f3f3f;
    const ll mod = 1e9 + 7;
    const int Max = 1e5 + 10;
    
    int n, m;
    int leader[Max];            //记录第i个领导者的位置
    int a[Max];                 //每次移动距离
    int vis[Max];
    
    int main()
    {
    #ifdef LOCAL
        //freopen("input.txt", "r", stdin);
        //freopen("output.txt", "w", stdout);
    #endif
        while (scanf("%d%d", &n, &m) != EOF)
        {
            memset(a, -1, sizeof(a));
            memset(vis, 0, sizeof(vis));
            bool ok = true;
    
            scanf("%d", leader + 1);
            for (int i = 2; i <= m; i++)
            {
                scanf("%d", leader + i);
                int temp = 0;
                int add = 0;
                if(leader[i] <= leader[i-1])
                {
                    add += n;
                }
                temp = leader[i] + add - leader[i-1];
    
                if (a[leader[i - 1]] == -1 || a[leader[i - 1]] == temp) //同一个人同一个a[i]没有问题
                {
                    if (vis[temp] && a[leader[i - 1]] == -1)            //不同的人有相同的a[i]
                    {
                        ok = false;
                    }
                    else
                    {
                        a[leader[i - 1]] = temp;
                        vis[temp] = true;
                    }
                }
                else
                {
                    ok = false;
                }
            }
    
            if (!ok)
            {
                printf("-1
    ");
            }
            else
            {
                for (int i = 1; i <= n; i++)
                {
                    if (a[i] != -1)
                    {
                        printf("%d ", a[i]);
                    }
                    else
                    {
                        for (int j = 1; j <= n; j++)
                        {
                            if (!vis[j])
                            {
                                printf("%d ", j);
                                vis[j] = true;
                                break;
                            }
                        }
                    }
                }
                printf("
    ");
            }
        }
        return 0;
    }
    818B

    818C Sofa Thief 

    题意:在一个 n * m 的房间内,有 d 个沙发,每个沙发占两个单位面积,我们将(x,y)视作一单位面积,给出每个沙发的位置x1,y1,x2,y2 ,代表这个沙发的位置为 (x1,y1),(x2,y2),保证没有两个及以上的沙发占用同一个位置,最后给出我们需要的沙发的信息cntL,cntR,cntB,cnrT,分别代表我们需要找的沙发的 左边沙发的个数,右边沙发的个数,底部沙发的个数,顶部沙发的个数,注意,只要两个沙发A,B,满足 A.x < B.x ,x = x1,x2,那么A就在B的左边,如果 A.y < B.y ,y = y1,y2,那么A在B的顶部,也就是说,y值大的在底部,问满足这个要求的沙发的编号,如果不存在,输出-1

    思路:思路很简单,不过很多细节需要注意,具体方法如下

      当前沙发左边的沙发数:所有左边界小于当前沙发右边界的沙发总数,
      1、如果找到第一个大于等于当前沙发右边界的,
        1) 如果当前沙发左右边界相等,那么此前的都是

        2)如果不相等,减去自身;
      2、如果没有大于等于当前沙发右边界的,那么此前所有的沙发都是的

      当前沙发右边的沙发数:所有右边界大于当前沙发左边界的沙发总数,
      1、如果找到第一个大于当前沙发左边界的,
        1)如果当前沙发左右边界相等,那么此后的都是

        2)如果不相等,减去自身
      2、如果没有找到大于当前沙发左边界的,那么就没有

      当前沙发底部的沙发数:所有上边界大于当前沙发下边界的沙发总数
      1、找到第一个大于当前沙发下边界的沙发,
        1) 如果上下边界相同,那么此后的都是

        2)如果不相等,减去自身
      2、如果没有大于当前沙发下边界的沙发,那么就没有

      当前沙发顶部的沙发数:所有下边界小于当前沙发上边界的沙发总数
      1、如果找到第一个大于等于当前沙发上边界的沙发
        1) 如果上下边界相同,那么此前的都是

        2)如果不相等,那么减去自身
      2、如果没有大于等于当前沙发上边界的沙发,那么全都是

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    #include<string>
    #include<fstream>
    #include<vector>
    #include<stack>
    #include <map>
    #include <iomanip>
    
    #define bug cout << "**********" << endl
    #define show(x, y) cout<<"["<<x<<","<<y<<"] "
    #define LOCAL = 1;
    using namespace std;
    typedef long long ll;
    const int inf = 0x3f3f3f3f;
    const ll mod = 1e9 + 7;
    const int Max = 1e5 + 10;
    
    struct Node
    {
        int x1, y1, x2, y2;
    } node[Max];
    
    
    int d, n, m;
    int cntL, cntR, cntT, cntB;
    int R[Max], L[Max], T[Max], B[Max];        //记录四个边界
    
    
    int main()
    {
    #ifdef LOCAL
        //freopen("input.txt", "r", stdin);
        //freopen("output.txt", "w", stdout);
    #endif
        while (scanf("%d%d%d", &d, &n, &m) != EOF)
        {
            for (int i = 1; i <= d; i++)
            {
                scanf("%d%d%d%d", &node[i].x1, &node[i].y1, &node[i].x2, &node[i].y2);
                if (node[i].x1 > node[i].x2)
                    swap(node[i].x1, node[i].x2);
                if (node[i].y1 > node[i].y2)        //大数为底部
                    swap(node[i].y1, node[i].y2);
                 
                L[i] = node[i].x1;                  //记录每个沙发的左边界
                R[i] = node[i].x2;                  //记录每个沙发的右边界
                B[i] = node[i].y1;                  //记录每个沙发的下边界
                T[i] = node[i].y2;                  //记录每个沙发的上边界,值大的为上边界
                //cout << "L: " << L[i] << " R: " << R[i] << " B: " << B[i] << " T: " << T[i] << endl;
            }
            scanf("%d%d%d%d", &cntL, &cntR, &cntT, &cntB);
             
            sort(R + 1, R + 1 + d);
            sort(L + 1, L + 1 + d);
            sort(B + 1, B + 1 + d);
            sort(T + 1, T + 1 + d);       //均升序排序
             
            int id = -1;
            for (int i = 1; i <= d; i++)            //枚举沙发
            {
                int ansL = lower_bound(L + 1, L + 1 + d, node[i].x2) - L;
                if (ansL == d + 1)                  //没有找到大于等于当前沙发右边界的沙发
                {
                    ansL = d - 1;
                }
                else
                {
                    ansL--;
                    if (node[i].x1 != node[i].x2)    //排除自身左边界的影响
                    {
                        ansL--;
                    }
                }
                //cout <<"ansL: "<<ansL<<endl;
                if (ansL != cntL)
                    continue;
                /**********************************************/
                int ansR = upper_bound(R + 1, R + 1 + d, node[i].x1) - R;
                if (ansR == d + 1)                  //没有找到大于当前沙发左边界的沙发,那么都是
                {
                    ansR = 0;
                }
                else
                {
                    ansR = d - ansR + 1;
                    if (node[i].x1 != node[i].x2)    //排除自身右边界的影响
                    {
                        ansR--;
                    }
                }
                //cout <<"ansR: "<<ansR<<endl;
                if (ansR != cntR)
                    continue;
                /**********************************************/
                int ansB = upper_bound(T + 1, T + 1 + d, node[i].y1) - T;
                if (ansB == d + 1)                    //没有找到大于当前沙发下边界的沙发,那么没有
                {
                    ansB = 0;
                }
                else
                {
                    ansB = d - ansB + 1;
                    if (node[i].y1 != node[i].y2)
                    {
                        ansB--;
                    }
                }
                //cout <<"ansB: "<<ansB<<endl;
                if (ansB != cntB)
                    continue;
                /**********************************************/
                int ansT = lower_bound(B + 1, B + 1 + d, node[i].y2) - B;
                if (ansT == d + 1)
                {
                    ansT = d - 1;
                }
                else
                {
                    ansT--;
                    if (node[i].y1 != node[i].y2)
                    {
                        ansT--;
                    }
                }
                //cout <<"ansT: "<<ansT<<endl;
                if (ansT != cntT)
                    continue;
                /**********************************************/
                id = i;
                break;
            }
            printf("%d
    ", id);
        }
        return 0;
    }
    
    //当前沙发左边的沙发数:所有左边界小于当前沙发右边界的沙发总数,
    //1、如果找到第一个大于等于当前沙发右边界的,
    //1) 如果当前沙发左右边界相等,那么此前的都是,2)如果不相等,减去自身;
    //2、如果没有大于等于当前沙发右边界的,那么此前所有的沙发都是的
    
    //当前沙发右边的沙发数:所有右边界大于当前沙发左边界的沙发总数,
    //1、如果找到第一个大于当前沙发左边界的,
    //1)如果当前沙发左右边界相等,那么此后的都是,2)如果不相等,减去自身
    //2、如果没有找到大于当前沙发左边界的,那么就没有
    
    //当前沙发底部的沙发数:所有上边界大于当前沙发下边界的沙发总数
    //1、找到第一个大于当前沙发下边界的沙发,
    //1) 如果上下边界相同,那么此后的都是,2)如果不相等,减去自身
    //2、如果没有大于当前沙发下边界的沙发,那么就没有
    
    //当前沙发顶部的沙发数:所有下边界小于当前沙发上边界的沙发总数
    //1、如果找到第一个大于等于当前沙发上边界的沙发
    //1) 如果上下边界相同,那么此前的都是,2)如果不相等,那么减去自身
    //2、如果没有大于等于当前沙发上边界的沙发,那么全都是
    818C
  • 相关阅读:
    [javaSE] 看博客学习多线程的创建方式和优劣比较和PHP多线程
    [javaSE] 看知乎学习反射
    [javaSE] 看知乎学习工厂模式
    [android] 新闻客户端主界面部分
    [PHP] 看博客学习观察者模式
    [javascript] 看知乎学习js事件触发过程
    [javascript] 看知乎学习js闭包
    [PHP] 看博客学习插入排序
    [android] ndk环境的搭建
    [android] 看博客学习hashCode()和equals()
  • 原文地址:https://www.cnblogs.com/winter-bamboo/p/11355591.html
Copyright © 2011-2022 走看看