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 }

原文地址:https://www.cnblogs.com/AaronChang/p/12147523.html

时间: 2024-10-06 17:14:41

Codeforces Round #609 (Div. 2) A-E简要题解的相关文章

Codeforces Round #609 (Div. 2)

A 简单题,输出 8n 和9n即可 因为8n是8的倍数,9n是9的倍数 而9n-8n=n成立 #include <iostream> #include <cstdio> using namespace std; int main(){ int n; cin >> n; printf("%d %d\n",9 * n, 8 * n); return 0; } B 给出两个n长的序列和一个m \((a_{i}+x) %m = b_{p}\) 这题我失误了,

Codeforces Round #609 (Div. 2) 【A,B,C】

题意:给一个n<=1e7,找两个合数a和b使得a-b的差为n. 构造a=3n,b=2n,必含有公因子n,只有当n是1的时候是特例. 1 #include<bits/stdc++.h> 2 3 using namespace std; 4 #define int long long 5 #define inf 0x3f3f3f3f3f3f 6 #define N 300009 7 int arr[]={2,3,5,7,13}; 8 signed main(){ 9 int n;scanf(

Codeforces Round #609 (Div. 2) 题解

Equation Modulo Equality Long Beautiful Integer Domino for Young K Integers Equation \[ Time Limit: 3 s\quad Memory Limit: 256 MB \] 这题做法很多,甚至可以直接暴力判断 view #include <map> #include <set> #include <list> #include <ctime> #include <

Codeforces Round #609 (Div. 2)E--K Integers(贪心+二分+树状数组+逆序对)

K Integers 参考博客:https://blog.csdn.net/Q755100802/article/details/103664555 [题意] 给定一个1到n的排列,可以交换相邻的两个元素. 现在定义一个函数f(x),表示在原排列中,通过交换操作,形成一个1,2,3....x的排列的子串,需要的最小操作步骤. 子串意味着这个排列必须是相邻的.现在你需要求出f(1),f(2),f(3)......f(n). [分析] 在1~x这几个元素相邻的情况下,因为最后排列不存在逆序对,根据贪

Codeforces Round #604 (Div. 2) 练习A,B题解

A题 链接 思路分析: 因为只需要做到相邻的不相同,利用三个不同的字母是肯定可以实现的, 所以直接先将所有的问号进行替换,比如比前一个大1,如果与后面的冲突,则再加一 代码(写的很烂): #include <bits/stdc++.h> using namespace std; int check( string a) { for (int i = 0; i < a.length(); ++i) { if (i==0) { if (a[i]==a[i+1]) { return 0; }

Codeforces Round #501 (Div. 3) F. Bracket Substring

题目链接 Codeforces Round #501 (Div. 3) F. Bracket Substring 题解 官方题解 http://codeforces.com/blog/entry/60949 ....看不懂 设dp[i][j][l]表示前i位,左括号-右括号=j,匹配到l了 状态转移,枚举下一个要填的括号,用next数组求状态的l,分别转移 代码 #include<bits/stdc++.h> using namespace std; const int maxn = 207;

Codeforces Round #536 (Div. 2)

目录 Codeforces Round #536 (Div. 2) A 题目大意 题解 卡点 C++ Code: B 题目大意 题解 卡点 C++ Code: C 题目大意 题解 卡点 C++ Code: D 题目大意 题解 卡点 C++ Code: E 题目大意 题解 卡点 C++ Code: F 题目大意 题解 卡点 C++ Code: Codeforces Round #536 (Div. 2) A 题目大意 给你一个\(n\times n(n\leqslant500)\)的矩阵,只包含.

Codeforces Round #428 (Div. 2)

Codeforces Round #428 (Div. 2) A    看懂题目意思就知道做了 #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a; i<=b; ++i) #define per(i,b,a) for (int i=b; i>=a; --i

Codeforces Round #424 (Div. 2) D. Office Keys(dp)

题目链接:Codeforces Round #424 (Div. 2) D. Office Keys 题意: 在一条轴上有n个人,和m个钥匙,门在s位置. 现在每个人走单位距离需要单位时间. 每个钥匙只能被一个人拿. 求全部的人拿到钥匙并且走到门的最短时间. 题解: 显然没有交叉的情况,因为如果交叉的话可能不是最优解. 然后考虑dp[i][j]表示第i个人拿了第j把钥匙,然后 dp[i][j]=max(val(i,j),min(dp[i-1][i-1~j]))   val(i,j)表示第i个人拿