ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

有趣的算法题(四)

2022-01-28 16:07:20  阅读:175  来源: 互联网

标签:min int pos cin -- 算法 有趣 include


Talk is cheap,show me the code
And Matching
div2C
泪目了,昨晚这个C我能很快做出来的,结果没看到k的取值,以为k能取任何值,推了一个多小时没出结果,回去看题发现k小于等于n-1

题意,给定两个数n和k(n一定是2的整数次幂而且n大于等于4,k小于等于n-1),在0到n-1中,要找n/2个做&运算的二元组,让这些个二元组加起来的和等于k

如果能组成,就输出你的方案中的二元组,如过不能,就输出-1

思路:
1.在二进制下观察后会发现,相邻的两项合并可以取得最大值,那么只有一种情况是-1,就是n为4,k为3,其他情况都是有解的。
2.0和n-1,1和n-2这样配对是0,所以用一个数组存0到n-1
3.当k不等于n-1时,只需要吧k和n-1作为一个二元组,剩下的让他们两两做&运算为0就行
4.当k等于n-1时,需要把n-2和0交换,再把1和2交换

5.首位向接输出数组中元素

#include <bits/stdc++.h>
using namespace std;
int a[20000000],t,n,k;
int main()
{
    for(cin>>t;t;t--)
    {
        cin>>n>>k;
        for(int i=0;i<=n-1;i++)
            a[i]=i;
        if(n==4&&k==3)
            cout<<-1<<endl;
        else
        {
             if(k<n-1)
                 swap(a[0],a[k]);
             else
             {
                 swap(a[k-1],a[0]);
                 swap(a[1],a[2]);
             }
        }
        for(int i=0;i<=n/2-1;i++)
            cout<<a[i]<<" "<<a[n-i-1]<<endl;
    }
    return 0;
}

Shifting Sort
题意自行去洛谷看

思路:这是选择排序的变型,我们每次从i到n确定最小值坐标,然后把最小值移动到i的位置就行了

#include <bits/stdc++.h>

using namespace std;

typedef pair<int, int> pii;

int main() {
    int t;
    for(cin>>t;t;t--)
    {
        int n;
        cin >> n;
        vector<int> a(n);
        vector<pii> actions;
        for (int i = 0; i < n; i++)
            cin >> a[i];
        for (int i = 0; i < n - 1; i++) 
        {
            int min_pos = i;
            for (int j = i + 1; j < n; j++)
                if (a[j] < a[min_pos])
                    min_pos = j;//确定最小值下标

            if (min_pos > i)//小优化,如果min_pos==i那么就不用进行操作了
            {
                actions.push_back({i, min_pos});//从i到最小值这个区间
                int opt = a[min_pos];
                for (int j = min_pos; j > i; j--)
                    a[j] = a[j - 1];
                a[i] = opt;
            }
        }
        cout << actions.size() << '\n';
        for (auto &lr: actions) {
            cout << lr.first + 1 << ' ' << lr.second + 1 << ' ' << lr.second - lr.first << '\n';
        }
    }
}

Swaps
给出两个长度为 nn 的序列 aa, bb,序列 aa 中的元素是 [1,2n][1,2n] 中的 奇数,序列 bb 的元素是 [1,2n][1,2n] 中的 偶数。 现可对两个序列进行操作,每次操作的步骤如下:

选取任意一个序列 aa 或 bb
选取一个下标 i ;; (i \in [1, n-1])i(i∈[1,n−1])
将选定序列的下标为 ii 的元素与下标为 (i+1)(i+1) 的元素交换
问最少经过多少次操作,使得序列 aa 的字典序小于序列 bb ?

思路:我们用一个数组去存储,这个数组下表m处存储的是m是第几个被输入进去的。因为我们所要用的次数只和这个元素有关。

洛谷的题解都很繁琐,可以看着这段代码,还是很好懂的。

#include <iostream>
#include <algorithm>
using namespace std;
int n,t,a[300001],i,j;
int main()
{
cin>>t;
while(t--){
	cin>>n;
	for(i=0;i<n;i++)
	cin>>j,a[j]=i;
	for(i=0;i<n;i++)
	cin>>j,a[j]=i;
	n*=2,i=j=n;
	while(n)
		j=min(a[n],j),i=min(a[n-1]+j,i),n-=2;
	cout<<i<<'\n';
}
}

期中j代表的是目前偶数移动到第一个位置位置的花费,i代表了总花费因为i=min(a[n-1]+j,i)中的a[n-1]+j

而我们是从后往前遍历的,后方偶数一定比前方的大,所以能确保后面的花费少就一定可以不用前面的

Carrying Conundrum
这个,,结论题或者数位DP也能做,然后位运算的这个结论也不是很清楚,就这样记住吧,数位DP那个思路说实在的,,太难了我不会而且一个C题如果卡这种程度的数位DP我赛时也写不出来。
题意:小a算数的时候满10不进一位,而是进两位,所以小b想知道,对于小a的计算结果有多少种方案让两个数相加能得到

结论:我们知道进位的话奇数位只能进位到奇数位上,偶数位只能进位到偶数位上,那么我们把奇数位的数记为x,偶数位上的数记为y最终答案就是(x+1)*(y+1)又因为0不能进位所以最终答案还要在这个基础上-2

#include <iostream>

using namespace std;

int main()
{
    int t;
    for(cin>>t;t;t--)
    {
        string s;
        cin>>s;
        long long odd=0,even=0;
        for(int i=0;i<(int)s.size();i+=2)
            odd=odd*10+(int)(s[i]-'0');
        for(int i=1;i<(int)s.size();i+=2)
            even=even*10+(int)(s[i]-'0');
        cout<<(odd+1)*(even+1)-2<<endl;
    }
    return 0;
}

思维题天花板?

Rings

#include <cstdio>
int t, n;
char s[20003];
int main() {
    scanf("%d", &t);
    while (t--) {
        scanf("%d%s", &n, s + 1);
        bool ok = 0;//0表示符合情况4
        for (int i = 1; i <= n; i++)
            if (s[i] == '0'){
                ok = 1;
                if (i > (n >> 1))//此时[1,i-1]长度大于等于[n/2]
                    printf("1 %d 1 %d\n", i, i - 1);
                else//否则[i+1,n]长度大于等于[n/2]
                    printf("%d %d %d %d\n", i, n, i + 1, n);
                break;
            }
        if (!ok)//此时两个子串[1,n-1],[2,n]长度相同,且数值一样
            printf("1 %d 2 %d\n", n - 1, n);
    }
    return 0;
}

Make a Power of Two
一道比较简单的思维题,不涉及算法暴力做就行。
思路:我们暴力的把2的0到63次方全部和给定的数去寻找最长公共子序列,对于2的0到63次幂每一个数都有:ans=目标串长度+给定串长度-2*最长公共子序列,最终答案就是所有ans中的最小值

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int t;
    for(cin>>t;t;t--)
    {
        string s,temp;
        int res=100000000;
        cin>>s;
        for(int i=0;i<=63;i++)
        {
            int cnt=0;
            temp=to_string(1ll<<i);
            for(int j=0;j<s.length();j++)
            {
                if(cnt<temp.length()&&temp[cnt]==s[j])
                    cnt++;
                res=min(res,(int)(temp.length()+s.length())-cnt*2);
            }
        }
         cout<<res<<endl;
    }
    return 0;
}

标签:min,int,pos,cin,--,算法,有趣,include
来源: https://blog.csdn.net/qq_35866893/article/details/122730046

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有