week18

1.

将 1,2,…,9 共 9 个数分成 3 组,分别组成 3 个三位数,且使这 3个三位数构成 1:2:3的比例,试求出所有满足条件的 3 个三位数。

本题是一道比较简单的分析题,从102到329依次分析即可

#include <iostream>
#include <cstring>
using namespace std;
int a[11], x, y, z,t;
int main()
{
	for (int i = 102; i <= 329; i++)
	{
		t = 0;
		x = i;
		y = i * 2;
		z = i * 3;
		for (int j = 1; j <= 3; j++)
		{
			if (a[x % 10] == 0&&x%10!=0)
				a[x % 10] = 1;
			else
			{
				t = 1;
				break;
			}
			if (a[y % 10] == 0&&y%10!=0)
				a[y % 10] = 1;
			else
			{
				t = 1;
				break;
			}
			if (a[z % 10] == 0&&z%10!=0)
				a[z % 10] = 1;
			else
			{
				t = 1;
				break;
			}
			x /= 10;
			y /= 10;
			z /= 10;
		}
		if (t == 0)
			cout << i << " " << i * 2 << " " << i * 3 << '\n';
		memset(a, 0, sizeof(a));
	}
	return 0;
}

2.

给出一个字符串 s,你需要执行 m个任务。每个任务给出两个下标 li,ri 和一个整数 ki(字符串的下标从 11 开始),表示你需要循环挪动 s 的子串 s[li...ri] ki 次。请从前到后依次执行给出的每个任务。

​ 字符串的循环挪动操作:将最后一个字符移到第一个字符的位置,并且将其他所有字符向右移一个位置。

​ 比如:如果字符串 s 是 abacaba,一个任务为 l1=3,r1=6,k1=1,那么答案为 abbacaa。接下来一个任务为 l2=1,r2=4,k2=2,那么我们会得到 baabcaa

输入格式

​ 第一行一个字符串 s,该字符串只包含小写英文字符。

​ 第二行一个整数 m,表示任务个数。

​ 接下来 m 行每行有三个整数 li,ri 和 ki。

输出格式

​ 输出执行了 m 个任务后的最终的字符串 s。

每次进行移动,字符串会被分成三部分:s的头部,需要挪动的子串s2,s的尾部。然后我们知道,挪动k次,就相当于把长度为k的字符串从尾部挪去头部,所以我们也可以把需要挪动的子串分成两部分,长度为k的s2尾部子串(将要挪去前面的那部分),和将要从前面移动到后面的s2的头部子串,所以我们整体可以把字符串分成三部分:

s的头部s1,需要挪动的子串的头部s2,需要挪动的子串的尾部s3,s的尾部s4

此时s还是s1+s2+s3+s4。经过挪动后就变成了s1+s3+s2+s4(因为s3要挪到s2的前面)。那我们就分别获取这四段字符串,再拼接起来即可。

下面附上代码

#include<iostream>
using namespace std;

#include<string>
#include<string.h>



int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    string str;
    cin >> str;
    int m,n=str.size();
    cin >> m;
    while (m--)
    {
        int l, r, k;
        cin >> l >> r >> k;
        int mod = (r - l + 1);
        string s1 = str.substr(0, l-1);
        string s2 = str.substr(l - 1, r - l - (k % mod) + 1);
        string s3 = str.substr(r-k%mod, k%mod);
        string s4 = str.substr(r, n - r + 1);
        if(l!=r)
            str = s1 + s3 + s2 + s4;
        
    }
    cout << str << '\n';
    return 0;
}

3.

本题直接暴力bfs搜就可以,题目说了就4位数,我们每次修改4个位置上的数,用0~9替换,替换后判断是否是质数即可,然后计算变换到b一共需要几步。

为了防止超时,我们可以先把所有四位数的质数都求出来,这样修改一个位置上的数后,就可以通过直接判断一个数是否在质数集里来判断它是不是质数了,顺便记录一下已经变换过的数,这样下次遇到这个数的时候我们直接不理他即可。

#include<iostream>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;



const int N = 2e6 + 50;
int f[100000], a[N],mymap[10000];


void get_p()
{
    for (int i = 1000; i <= 9999; i++)
    {
        bool flag = true;
        for (int j = 2; j * j <= i; j++)
        {
            if (i % j == 0)
            {
                flag = false;
                break;
            }
        }
        if (flag)
        {
            mymap[i] = 1;
        }
    }
}

int main()
{
    int t;
    cin >> t;
    get_p();
    while (t--)
    {
        int a, b;
        cin >> a >> b;
        if (a == b)
        {
            cout << 0 << endl;
            continue;
        }
        queue<int>que;
        que.push(a);
        memset(f, 0, sizeof f);
        int res = 1;
        bool flag = false;
        while (!que.empty())
        {
            int len = que.size();
            for (int i = 0; i < len; i++)
            {
                int num = que.front();
                que.pop();
                for (int j = 10; j <= 10000; j*=10)
                {
                    int l = num / j, r = num % (j/10);
                    for (int k = 0; k <= 9; k++)
                    {
                        int ans = l * j + k*(j/10) + r ;
                        if (ans == b)
                        {
                            flag = true;
                            break;
                        }
                        if (f[ans] == 0 && mymap[ans] == 1)
                        {
                            f[ans] = 1;
                            que.push(ans);
                        }
                    }
                    if (flag)break;
                }
                if (flag)break;
            }
            if (flag)break;
            res++;
        }
        cout << res << '\n';
    }
    return 0;
}

4.

输入正整数 k,找到所有的正整数 y≤x, 使得 1k=1x+1y1。

输入格式

输入一个正整数 k(1≤k≤107)。

输出格式

输出一个数,表示满足条件的x,y的个数。

一道简单的分析题,y<=2k;注意开longlong即可

#include<iostream>
using namespace std;
int ans;
int main()
{
	long long k, y;
	cin >> k;
	for (y = k + 1; y <= 2 * k; y++) {


		if (((k * y) % (y - k)) == 0)
		{
			ans++;
		}
	}
	cout << ans;
	return 0;
}  

5.

题目描述

有一个长度为 ∑ai 的木板,需要切割成 n 段,每段木板的长度分别为 a1,a2,…,an。

每次切割,会产生大小为被切割木板长度的开销。

请你求出将此木板切割成如上 n 段的最小开销。

输入格式

第 11 行一个正整数表示 n。

第 22 行包含 n个正整数,即 a1,a2,…,an。

输出格式

输出一个正整数,表示最小开销。

我们反过来,把切割过程反向的看作n个小木板合成一条木板的最小花费
最小堆嘛,就是每次都把当前数组里面最小的两个数结合,它们的和就是本次的花费。
直接用stl的优先队列实现。
优先队列默认是最大堆,而这一题要最小堆,所以修改一下

声明一个元素类型为 long long 的最小堆

priority_queue<long long, vector<long long>, greater<long long>>

下面附上代码

#include <algorithm>
#include <cstring>
#include <iostream>
#include <queue>
#include <string>
#include <vector>

using namespace std;

priority_queue<long long, vector<long long>, greater<long long>> p;
int n, a;
int main() {
cin>>n;
    for (int i = 0; i < n; i++) {
    cin>>a;
    p.push(a);
  }
  long long sum = 0, cnt = 0;
  for (int i = 0; i < n - 1; i++) {
    cnt = 0;
    cnt += p.top(), p.pop();
    cnt += p.top(), p.pop();
    sum += cnt;
    p.push(cnt);
  }
  cout<<sum;
  return 0;
}

6.

长江游艇俱乐部在长江上设置了 n 个游艇出租站 1,2,⋯ ,。游客可在这些游艇出租站租用游艇,并在下游的任何一个游艇出租站归还游艇。游艇出租站 i 到游艇出租站 j 之间的租金为 r(i,j)(≤i<j≤n)。试设计一个算法,计算出从游艇出租站 1 到游艇出租站 n 所需的最少租金。

输入格式

第一行中有一个正整数 n,表示有 n 个游艇出租站。接下来的 n−1 行是一个半矩阵r(i,j)(1≤i<j≤n)。

输出格式

输出计算出的从游艇出租站 1到游艇出租站 n 所需的最少租金。

基础的动态规划题,状态转移方程为

dp[i] = min(dp[i], dp[j] + a[j][i];

下面附上代码

#include <iostream>
using namespace std;
int n, a[205][205],dp[205];
int main()
{
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		for (int j = i + 1; j <= n; j++)
			cin >> a[i][j];
	}
	dp[2] = a[1][2];
	for (int i = 3; i <= n; i++)
	{
		dp[i] = a[1][i];
		for (int j =  2; j < i; j++)
		{
			dp[i] = min(dp[i], dp[j] + a[j][i]);
		}
	}

	cout << dp[n];
	return 0;
}

 7.

某小学最近得到了一笔赞助,打算拿出其中一部分为学习成绩优秀的前 5 名学生发奖学金。期末,每个学生都有 3 门课的成绩:语文、数学、英语。先按总分从高到低排序,如果两个同学总分相同,再按语文成绩从高到低排序,如果两个同学总分和语文成绩都相同,那么规定学号小的同学 排在前面,这样,每个学生的排序是唯一确定的。

任务:先根据输入的 3 门课的成绩计算总分,然后按上述规则排序,最后按排名顺序输出前五名名学生的学号和总分。注意,在前 5 名同学中,每个人的奖学金都不相同,因此,你必须严格按上述规则排序。例如,在某个正确答案中,如果前两行的输出数据(每行输出两个数:学号、总分) 是:

7 279
5 279

这两行数据的含义是:总分最高的两个同学的学号依次是 7 号、5 号。这两名同学的总分都是 279 (总分等于输入的语文、数学、英语三科成绩之和) ,但学号为 7 的学生语文成绩更高一些。如果你的前两名的输出数据是:

5 279
7 279

则按输出错误处理,不能得分

本题掌握结构体排序的方法即可

#include <iostream>
#include <algorithm>
using namespace std;
struct aa
{
	int x, y, z, sum, t;
}a[305];
bool cmp(aa x, aa y)
{
	if (x.sum == y.sum)
	{
		if (x.x == y.x)
			return x.t < y.t;
		return x.x > y.x;
	}
	return x.sum > y.sum;
}
int main()
{
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i].x >> a[i].y >> a[i].z;
		a[i].t = i;
		a[i].sum = a[i].x + a[i].y + a[i].z;
	}
	sort(a + 1, a + n + 1, cmp);
	for (int i = 1; i <= 5; i++)
	{
		cout << a[i].t << " " << a[i].sum << '\n';
	}
	return 0;
}

8.

cc有一个背包,背包的体积为w,有n个物品,每一个物品的体积为ai

cc希望将其中的一些物品放入他的背包中,他希望这些物品的体积之和至少是背包体积的一半,并且不超过背包的体积,即 ⌈w/2⌉≤sum≤w

请你帮cc判断这些物品中有没有符合条件的物品组合,如果有输出"YES", 没有输出"NO"

cc至少会拿一个物品

本题遍历一下他给的物品,小于等于背包体积一半的都装背包里,不满足条件的直接看那个货物是不是就在w/2~w之间。

首先你小于一半的装背包里,当你背包已经装了一半的时候已经满足条件了,不满足一半的时候你装一个小于一半的肯定也不会超。

#include<iostream>
#include <vector>
#include<algorithm>
using namespace std;

int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        long long n, m;
        cin >> n >> m;
        long long res = 0;
        vector<long long>v(n);
        bool flag = false;
        for (int i = 0; i < n; i++)
        {
            cin >> v[i];
            if (!flag&&v[i] >= (m + 1) / 2 && v[i] <= m)
            {
                cout << "YES" << endl;
                flag = true;
            }
        }
        if (flag)continue;
        for (int i = 0; i < n; i++)
        {
            if (v[i] < (m + 1) / 2)
            {
                res += v[i];
            }
            if (res >= (m+1) / 2 && res <= m)
            {
                flag = true;
                cout << "YES" << endl;
                break;
            }
            if (res > m)break;
        }
        if (!flag)cout << "NO" << endl;
    }
    return 0;
}

9.

有一个由 n个元素组成的序列 a1,a2,…,an;最初,序列中的每个元素满足 ai=i。

对于每次操作,你可以交换序列中第 i 个元素和第 j个元素当且仅当满足 |i−j|=di|。

题目给出序列 b1,b2,…,bn 和 d1,d2,…,dn,询问是否可以通过若干次交换,使得序列 a 和序列 b 完全相同。

输入格式

第 1 行一个正整数 n,含义如上。

第 2 行 n个正整数表示 b1,b2,…,bn。

第 3 行 n 个正整数表示 d1,d2,…,dn。

输出格式

若能,输出 YES;否则输出 NO


对于本题我们可以通过并查集,把i-d[i]和i+d[i]和i连接成一个连通块,说明第i个位置可以是i-d[i]和i+d[i]这两个值(但要注意一下,如果i-d[i]<=0或者i+d[i]>0,那就不要合并了),我们用这种方法把所有的数连成连通块后,在依次判断i和b[i]是否处于同一个连通块中,要是处于,就说明b[i]总有机会可以换到第i个位置上。一旦有一个不相同的,就输出no。
 

#include<iostream>
#include <vector>
using namespace std;



const int N = 110;
int f[N],mysize[N];

int find(int x)
{
    if (x != f[x])
        f[x] = find(f[x]);
    return f[x];
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int n, x, y;
    cin >> n;
    vector<int>v(n);
    for (int i = 0; i < n; i++)cin >> v[i];
    for (int i = 1; i <= n; i++)f[i] = i, mysize[i] = 1;
    for (int i = 1; i <= n; i++)
    {
        cin >> y;
        int a = find(i), b;
        if (i - y > 0)
        {
            b = find(i - y);
            if (a != b)
            {
                if (mysize[a] > mysize[b])swap(a, b);
                f[a] = b;
                mysize[b] += mysize[a];
            }
        }
        if (i + y <= n)
        {
            b = find(i + y);
            if (a != b)
            {
                if (mysize[a] > mysize[b])swap(a, b);
                f[a] = b;
                mysize[b] += mysize[a];
            }
        }
    }
    for (int i = 1; i <= n; i++)
    {
        int a = find(i), b = find(v[i - 1]);
        if (a != b)
        {
            cout << "NO" << '\n';
            return 0;
        }
    }
    cout << "YES";
    return 0;
}

10.

题目描述

设有 n 个正整数 a1​…an​,将它们联接成一排,相邻数字首尾相接,组成一个最大的整数。

输入格式

第一行有一个整数,表示数字个数 n。

第二行有 n 个整数,表示给出的 n 个整数 ai​。

输出格式

一个正整数,表示最大的整数

本题对依次对两个字符串相加进行排序即可;

#include<iostream>
#include<string>
#include<algorithm>
using namespace std;

string s[25]; int n;
bool cmp(string a,  string b) { 
    return (a + b > b + a);
}
int main() {
    cin >> n;
    for (int i = 1; i <= n; ++i) cin >> s[i];
    sort(s + 1, s + n + 1, cmp);
    for (int i = 1; i <= n; ++i) cout << s[i];
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值