zoukankan      html  css  js  c++  java
  • Codeforces Round #609 (Div. 2) A-E简要题解

    contest链接:https://codeforces.com/contest/1269

    A. Equation

    题意:输入一个整数,找到一个a,一个b,使得a-b=n,切a,b都是合数

    思路:合数非常多,从1开始枚举b,a就是b+n,每次check一下a,b是否是合数,是的话直接输出,break即可

    AC代码:

     1 #include<iostream>
     2 #include<string>
     3 #include<vector>
     4 #include<cstring>
     5 #include<cstdio>
     6 #include<algorithm>
     7 #include<cmath>
     8 using namespace std;
     9 typedef long long ll;
    10 ll mod = 1e9+7;
    11 const int maxn = 2e5+10;
    12 bool check(ll x){
    13     for(int i = 2;i<=sqrt(x);i++){
    14         if(x%i == 0) return true; 
    15     }
    16     return false;
    17 }
    18 int main(){
    19     ll n;cin>>n;
    20     ll cur = 1;
    21     while(1){
    22         if(check(cur)&&check(cur+n)){
    23             cout<<cur+n<<" "<<cur;
    24             return 0;
    25         }
    26         cur++;
    27     }
    28     return 0;
    29 }

    B. Modulo Equality

    题意:有两个序列a,b,要求找到一个相对最小的x,让a序列中的所有元素+x再mod m变为序列b,两个序列内部都可以随意交换

    思路:可以发现数据范围很小,直接就可以暴力做。首先对a序列和b序列都进行一下从小到大的排序,首先判一下当前的a序列和b序列是否相等,如果相等直接输出0即可。不相等再进行枚举,以b[1]为基准,枚举a[i]中的每个元素,计算一下b[1]和a[i]模运算差值,让a序列所有的元素加上这个差值之后再判断一下是否和b[i]中的每一个元素相等,取最小的x即可。

    AC代码:

    #include<iostream>
    #include<string>
    #include<vector>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    ll mod = 1e9+7;
    const int maxn = 2e5+10;
    int main(){
        ll cur = 1;
        ll n,m;cin>>n>>m;
        ll a[2005],b[2005];
        for(int i = 1;i<=n;i++) cin>>a[i];
        for(int j = 1;j<=n;j++) cin>>b[j];
        sort(a+1,a+n+1);
        sort(b+1,b+n+1);
        int f = 0;
        for(int i = 1;i<=n;i++){
            if(a[i]!=b[i]) f = 1;
        }
        if(f == 0) {
            cout<<0;
            return 0;
        }
        ll ans = 1e9+5;
        ll c[2005];
        for(int i = 1;i<=n;i++){
            ll x = b[1]>a[i]?b[1]-a[i]:b[1]+m-a[i];
            for(int j = 1;j<=n;j++){
                c[j] = (a[j]+x)%m;
            } 
            sort(c+1,c+n+1);
            ll f = 0;
            for(int j = 1;j<=n;j++){
                if(c[j]!=b[j]) {
                    f = 1;
                    break;
                }
            }
            if(f == 0){
                ans = min(ans,x);
            }
        }
        cout<<ans;
        return 0;
    }

    C. Long Beautiful Integer

    题意:给一个长度为n(长度数据范围2e5)的数字,要求把n转化为大于n且尽可能小的数,使得新的数字每一位 bi = bi+k。

    思路:首先对数的前k位进行存储,第k位之后,每一位的数字都受到前k位影响,因为前k位一旦有变换,k位之后必定也需要改变才能满足bi = bi+k,那么只需要对前k位进行枚举即可,每次让前k位组成的数字+1,再变换k位之后的数字,如果这个数字大于最初的n,那么就是break,已经是最小的答案了。同时需要注意一下进位的问题,比如19999,+1之后变为20000,这个也需要处理一下。

    AC代码:

        #include<iostream>
        #include<string>
        #include<vector>
        #include<cstring>
        #include<cstdio>
        #include<algorithm>
        #include<cmath>
        using namespace std;
        typedef long long ll;
        ll mod = 1e9+7;
        const int maxn = 2e5+10;
        int main(){
            ll n,k;cin>>n>>k;
            string s;
            cin>>s;
            string ans = s;
            string ak = "";
            for(int i = 0;i<k;i++){
                ak+=s[i];
            }
            for(int i = k;i<n;i++){
                ans[i] = ak[i%k];
            }
            for(int i = k;i<n;i++){
                if(s[i]<ans[i]){
                    break;
                }
                if(s[i] == ans[i]){
                    continue;
                }
                if(s[i]>ans[i]){
                    int cur = k - 1;
                    while(ak[cur] == '9'){
                        ak[cur] = '0';//处理进位,让所有的9变为0,遇到第一个不是9的让其+1即可
                        cur--;
                    }
                    ak[cur] = ak[cur] + 1;
                    break;
                }
            }
            for(int i = 0;i<n;i++){
                ans[i] = ak[i%k];
            } 
            cout<<ans.size()<<endl;
            cout<<ans;
            return 0;
        }

    D. Domino for Young

    题意:给一个不规则的网格,在上面放置多米诺骨牌,多米诺骨牌长度要么是1x2,要么是2x1大小,问最多放置多米诺骨牌的数量。

    思路:首先这是一个结论题,对每个方格进行染色,一个方格染黑色,周围邻近的就染白色,答案就是黑色方格数量和白色方格数量的最小值。这个结论可以用二分图进行证明:把问题抽象成最大二分图匹配,每两个点之间连一条边。一个格子和周围格子连一条边,如果一个格子周围的还没被匹配,那么匹配数+1。如果一个格子周围已经全部被匹配完,那么该格子可以增广到任意一个为匹配位置,匹配数+1。所以只要在另一种颜色格子数量充沛的情况下,每一次匹配都能对匹配数贡献1,所以答案就是两种颜色的最小值。

    AC代码:

    #include<iostream>
    #include<string>
    #include<vector>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    ll mod = 1e9+7;
    const int maxn = 2e5+10;
    int main(){
        ll black = 0 , white = 0;
        int n;cin>>n;
        int cur = 0;
        for(int i = 0;i<n;i++){
            ll a ;cin>>a;
            if(cur == 0){
                black +=(a/2+a%2);
                white +=a/2;
                cur = 1;
            }
            else{
                cur = 0;
                black +=a/2;
                white +=(a/2+a%2);
            }
        } 
        ll ans = min(black,white);
        cout<<ans;
        return 0;
    }

    E. K Integers

    题意:给一个序列P1,P2,P3,P4....Pi,每次可以交换两个相邻的元素,执行最小次数的交换移动,使得最后存在一个子段1,2,…,k,这是题目所定义的f(k),题目要求求出所有的f(n),并依次输出。

    思路:首先考虑逆序对问题,比如3 2 1 4这个序列,要使其变为1 2 3 4,最小的移动次数是这个序列中逆序对之和,2+1 = 3,逆序对是(3,2) (3,1)(2,1),但是在比如序列3 5 2 1 6 7 4 8 9,求f(4)怎么做?首先是不是把1 2 3 4这个序列聚成在一起,相连在一起,再去计算逆序对个数,两个过程所花费相加就是答案。那么这个题目就分为两个过程,1.聚合n个数字在一起。2.求逆序对的个数,两者花费相加就行。第1个过程如果使得聚合步数最少呢?其实就是求出聚合后的最中间的位置,其他所有的数字向这个位置靠近所花费的移动次数是最少的,这个过程可以用二分做。第2个过程可以用树状数组,也可以用线段树做。输入的时候记录每个数字的位置,建两个树状数组,一个树状数组维护数字出现的次数,用来求逆序对个数,另一个树状数组维护各个数字在原序列的位置。

     1 #include<iostream>
     2 #include<string>
     3 #include<vector>
     4 #include<cstring>
     5 #include<cstdio>
     6 #include<algorithm>
     7 #include<cmath>
     8 using namespace std;
     9 typedef long long ll;
    10 ll mod = 1e9+7;
    11 const int maxn = 2e5+10;
    12 ll t[maxn],cnt[maxn]; 
    13 ll pos[maxn];
    14 int n;
    15 inline int lowbit(ll x){
    16     return x&(-x);
    17     ///算出x二进制的从右往左出现第一个1以及这个1之后的那些0组成数的二进制对应的十进制的数
    18 }
    19 void add(ll *b , int x, int k) {//单点修改 
    20   while (x <= n) {  //不能越界
    21     b[x] = b[x] + k;
    22     x = x + lowbit(x);
    23   }
    24 }
    25 ll getsum(ll *b,int x) {  // a[1]……a[x]的和
    26   ll ans = 0;
    27   while (x > 0) {
    28     ans = ans + b[x];
    29     x = x - lowbit(x);
    30   }
    31   return ans;
    32 }
    33 int main(){
    34     ios::sync_with_stdio(false);
    35     cin.tie(0);
    36     cin>>n;
    37     for(int i = 1;i<=n;i++){
    38         int t;
    39         cin>>t;
    40         pos[t] = i;//记录t的位置 
    41     }
    42     ll inv = 0;//记录逆序对的个数 
    43     for(int i = 1;i<=n;i++){
    44         inv += (i-1-getsum(t,pos[i]));//每次统计逆序对的个数 ,累加即可 
    45         add(t,pos[i],1);//在t数组上的pos[i]位置上+1 
    46         add(cnt,pos[i],pos[i]);// cnt数组上维护所有数组的位置, 
    47         if(i==1){
    48             cout<<0<<" ";
    49             continue;
    50         }
    51         int mid,l = 1,r = n;
    52         while(l<=r){//二分枚举中最中间的位置,所有数字向这个位置靠近 
    53             mid = (l+r)>>1;
    54             if(getsum(t,mid)*2<=i){
    55                 l = mid+1;
    56             }
    57             else{
    58                 r = mid-1;
    59             }
    60         }    
    61         ll ans = 0;
    62         ll cntL = getsum(t,mid);//cntL在mid左边需要的数字个数之和 
    63         ll cntR = i - cntL;//cntR是mid右边需要的数字个数之和 
    64         ll indexL = getsum(cnt,mid);//mid左边需要数字的位置之和 
    65         ll indexR = getsum(cnt,n)-indexL;//mid右边需要数字的位置之和 
    66         ans+=((mid+(mid-cntL+1))*cntL)/2-indexL;//累加mid左边数字靠近邻近mid位置所需要的移动次数 
    67         ans+=(indexR-((mid+1+(mid+cntR))*cntR)/2);//累加mid右边数字靠近邻近mid位置所需要的移动次数 
    68         cout<<ans+inv<<" ";//逆序对+聚合移动次数为答案 
    69     }
    70     return 0;
    71 }
  • 相关阅读:
    HTML元素解释
    Java命名规范
    HDU 1058 Humble Numbers(DP,数)
    HDU 2845 Beans(DP,最大不连续和)
    HDU 2830 Matrix Swapping II (DP,最大全1矩阵)
    HDU 2870 Largest Submatrix(DP)
    HDU 1421 搬寝室(DP)
    HDU 2844 Coins (组合背包)
    HDU 2577 How to Type(模拟)
    HDU 2159 FATE(二维完全背包)
  • 原文地址:https://www.cnblogs.com/AaronChang/p/12147523.html
Copyright © 2011-2022 走看看