week17

老师为即将毕业的同学们准备了一场舞会,有2N个同学会参加这场舞会,他们会被分成N对跳舞,每个人有一个编号,如果编号为i的同学和编号为j的同学配对,那么这一对的满意度是Ai,j(i<j),我们规定这个舞会的满意度为每一队的满意度的异或和,也就是说,当同学们分成N组后,第i对同学的满意度为Ai,那么舞会的满意度为A1⊕A2⊕...AN

请你求出本场舞会满意度的最大值

输入描述

第一行给出一个数N,有2N个人参加舞会

接下来给出一个矩阵表示i和j配对时的满意度

A1,2,A1,3,...A1,2N

A2,3,...A2,2N

.. .. ..

A2N−1,2N

其中1≤N≤8,0≤Ai,j<=2^30

输出描述

输出本场舞会满意度的最大值

本题数据很少,但需要搜索的次数很多,所以需要用到减枝;

下面附上代码

#include <bits/stdc++.h>
using namespace std;
bool vis[20];
int a[20][20];
int ans, n;
void dfs(int step, int res) // step为当前已经匹配的对数,res是当前的异或和
{
    if (step == n) //已全部匹配更新答案
    {
        ans = max(ans, res);
        return;
    }
    int i;
    for (i = 2; i <= n + n - 1; i++)
    {
        if (!vis[i]) //找到1~2n中第一个未被匹配的数(剪枝)
            break;
    }
    for (int j = i + 1; j <= n + n; j++)
    {
        if (vis[j] == 0) //未被匹配
        {
            vis[i] = 1, vis[j] = 1; //匹配
            dfs(step + 1, res ^ a[i][j]);
            vis[i] = 0, vis[j] = 0; //取消标记
        }
    }
}
int main()
{
    cin >> n;
    for (int i = 1; i <= n + n - 1; i++)
        for (int j = i + 1; j <= n + n; j++)
            cin >> a[i][j];
    vis[1] = 1;                      // 1肯定会被匹配,直接加入匹配(剪枝)
    for (int i = 2; i <= n + n; i++) //枚举与1匹配的位置
    {
        vis[i] = 1;
        dfs(1, a[1][i]);
        vis[i] = 0;
    }
    cout << ans;
}

2.

小明的数学很好,所以他认为世界上所有的数学问题都很简单。

但是有一天,他遇到了一个他无法解决的数学问题,所以他请求你帮助他。

小明会给你两个数字 a 和 b ,然后你应该选择一个正奇数 x和一个正偶数 y ,你可以让 a 加上 x 或让 a 减去 y,在一次运算中。你应该在最少的操作中把 a 变成 b。请注意,在同一次运算中,你不允许改变 x 和 y 的值。

输入格式

在第一行,有一个整数 T。

接下来T行每行2个整数 a、b、。表示由小明给出的数字。

输出格式

一个数,表示将 a 变为 b 所需的最小操作数。

本题是一道较为简单的数学分析题,直接上代码解释了

#include <iostream>
using namespace std;
int a, b,t;
int main()
{
	cin >> t;
	while (t--)
	{
		cin >> a >> b;
		if (a == b)
			cout << 0<<'\n';
		else if (a > b)
		{
			if (a % 2 == 0 && b % 2 == 0 || a % 2 != 0 && b % 2 != 0)
				cout << 1<<'\n';
			else
				cout << 2<<'\n';
		}
		else
		{
			if (a % 2 == 0 && b % 2 == 0 || a % 2 != 0 && b % 2 != 0)
			{
				int x = (b - a) / 2;
				if (x % 2 == 0)
					cout << 3 << '\n';
				else
					cout << 2 << '\n';
			}
			else
				cout << 1<<'\n';
		}
	}
	return 0;
}

3.

题目描述

约翰的 n 头奶牛每年都会参加“哞哞大会”。

哞哞大会是奶牛界的盛事。集会上的活动很多,比如堆干草,跨栅栏,摸牛仔的屁股等等。

它们参加活动时会聚在一起,第 i 头奶牛的坐标为 xi,没有两头奶牛的坐标是相同的。

奶牛们的叫声很大,第 i 头和第 j 头奶牛交流,会发出 max{vi,vj}×|xi−xj|的音量,其中 vi 和 vj分别是第 i 头和第 j头奶牛的听力。

假设每对奶牛之间同时都在说话,请计算所有奶牛产生的音量之和是多少。

输入格式

第 1 行:单个整数 n,1≤n≤3×10^4。

第 2 行到第 n+1行:第 i+1 行有两个整数 vi和 xi(1≤vi,xi≤3×104)。

输出格式

输出单个整数,表示所有奶牛产生的音量之和。

本题是一道非常基础的计算题,硬算即可

#include <iostream>
#include <algorithm>
#include <math.h>
using namespace std;
const int N = 3e4 + 5;
struct aa
{
	int x;
	int v;
}a[N];
long long n, ans,b,c;
bool cmp(aa z, aa y)
{
	return z.x < y.x;
}
int main()
{
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin>>a[i].v>>a[i].x;
	}
	sort(a + 1, a + n + 1, cmp);
	for(int i=1;i<=n;i++)
		for (int j = i + 1; j <= n; j++)
		{
			ans += max(a[i].v, a[j].v) * (a[j].x - a[i].x);
		}
	cout << ans;
	return 0;
}

4.

给你一个有 n 个元素的数组 a 。你可以对它进行如下操作,次数不限。

从一个偶数大小为 2k 的数组中选择一些从位置 l 开始的子数组(1≤l≤l+2⋅k−1≤n1≤l≤l+2⋅k−1≤n, k≥1k≥1) ,对于 0 到 k-1(包括)之间的每一个 i ,将值 al+k+i 分配给 al+i 。

例如,如果 a=[2,1,3,4,5,3] ,然后选择 l=1 和 k=2 ,应用这个操作,数组将变成 a=[3,4,3,4,5,3]。

请找出使数组中所有元素相等所需的最少操作数(可能是零)。

输入格式
输入由多个测试案例组成。第一行包含一个整数 t(1≤t≤2⋅104)–测试案例的数量。测试用例的描述如下。

每个测试用例的第一行包含一个整数 n(1≤n≤2⋅10^5 )–数组的长度。

每个测试用例的第二行包含 n 个整数 a1,a2,…,an(1≤ai≤n)–数组的元素a。

输出格式
打印 t 行,每行包含相应测试案例的答案–用给定的操作使数组中所有元素相等所需的最小操作数。

首先由题意我们就可以看出,要想数组一样,只能是改成全部和最后一个数一样,因为只能通过后面的数来修改前面的数,所以要想数组一样只能是吧整个数组改成最后一个的样子。

我们就从后面开始遍历,记录所有和最后一个数相同的个数,记作ans,在此过程种,一旦遇到和最后一个不一样的,我们就直接把这个数改成一样的,修改次数++,但一个个修改太麻烦了,我们可以直接把后面的ans个相同的数赋给前面的ans个数,这样整个数组就有ans*2个位置都是相同的数了(也不用管赋值前的数是什么样,如果是和最后一样也没影响,如果不一样那就正好改成一样的)

下面附上代码

#include<iostream>
using namespace std;
const int N=2e5+5;
int a[N],res;
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int t;
    cin >> t;
    while (t--)
    {
        int n;
        cin >> n;
        for (int i = n-1; i >=0 ; i--)
            cin >> a[i];
        int num = a[0], res = 0, ans = 1;
        while (ans < n)
        {
            if (a[ans] == num)ans++;
            else
            {
                res++;
                ans *= 2;
            }
        }
        
        cout <<res<<'\n';
    }
    return 0;
}

5.

​ 给出一个整数 n,请解决下面的问题:

​ 使 f(x)=(不超过 x 且与 x 具有相同位数的正整数的个数)。

​ 求出 f(1)+f(2)+...+f(n),结果对 998244353 取模。

输入格式

​ 一个整数 N。

输出格式

​ 一个整数——上面问题的答案,并对 998244353取模。

通过观察规律可以发现,f(n)是由个等差数列组成的,因此我们可以用等差数列求和的方式来求解,过程中注意取模即可。

#include<iostream>
using namespace std;

const int MOD = 998244353;

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    long long n, res = 0, num = 0, power = 10;
    cin >> n;
    while (1)
    {
        if (n > power - 1)
        {
            long long x = (1 + power - power / 10) % MOD;
            long long y = ((power - power / 10)) % MOD;
            res =res+ (x*y/2)%MOD;
            res %= MOD;
        }
        else
        {
            long long x = (1 + n - power / 10 + 1) % MOD;
            long long y = ((n - power / 10 + 1)) % MOD;
            res = res+ (x*y/2)%MOD;
            res %= MOD;
            break;
        }
        power *= 10;

    }
    cout << res%MOD <<'\n';
    return 0;
}

6.

对于给定的数字 a , b,当整数 n在十进制下的所有数位都为 a 或 b时,我们称 n是“好数”

对于好数 n ,当 n在十进制下每一位的数字之和也为“好数”时,我们称 n是一个“完美数”

请你求出有多少 m 位数是“完美数”

输入格式

输入一行三个整数 a , b, m , 含义如题面所示 (1≤m≤106,1≤a,b≤9)。

输出格式

输出一行一个整数表示完美数的数量 , 由于答案可能很大 , 请你将答案对 109+7109+7 取模

这题要求是,找出m位数的完美数。注意是m位数,比如5位数那就是10w,这里m最多可以取到10^6,这肯定会超时的,所以说也不用想着通过枚举来判断每一位是不是a或b了。但是我们完全可以反过来,既然好数是只有a和b的是数,那我们就用a和b排列出m位数,那他就是好数了。但完美数怎么办呢,一样的想法,完美数是好数各位数加起来仍然是好数,这里好数只有a和b组成,那么各位数之和就是x个a+y个b。我们只要枚举a或b的个数(x或y),然后计算出x*a+y *b,再看这个和是否是好数即可。如果是好数,那么说明x个a和y个b组成的m位数就将是个完美数。然后只要计算出他们的排列组合即可。

下面附上代码

#include<iostream>
using namespace std;

const int MOD = 1e9 + 7, N = 1e6 + 10;

long long fact[N], infact[N];

long long qmi(int a, int b)//计算组合数
{
    long long res = 1;
    while (b)
    {
        if (b & 1) res = res * a % MOD;
        a = a * (long long)a % MOD;
        b >>= 1;
    }
    return res;
}

void init()//计算组合数
{
    fact[0] = infact[0] = 1;
    for (int i = 1; i < N; i++)
        fact[i] = fact[i - 1] * i % MOD;

    infact[N - 1] = qmi(fact[N - 1], MOD - 2);
    for (int i = N - 2; i; i--)
        infact[i] = infact[i + 1] * (i + 1) % MOD;
}

int C(int a, int b)//计算组合数
{
    return (fact[a] * infact[b] % MOD * infact[a - b] % MOD) % MOD;
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int a, b, m;
    cin >> a >> b >> m;
    init();
    char c = a + '0', d = b + '0';
    int x;
    long long res = 0;
    for (int i = 0; i <= m; i++)
    {
        x = m - i;
        long long num = x * a + i * b;
        bool flag = true;
        while (num)
        {
            if (num % 10 != a && num % 10 != b)
            {
                flag = false;
                break;
            }
            num /= 10;
        }
        if (!flag)continue;
        res = (res + C(m,i)) % MOD;
    }
    cout << (res%MOD) <<'\n';
    return 0;
}

7.

又是大家最喜欢的01序列问题了呢

这次的问题非常的简单,cc觉得一个01序列中两个1之间至少要有k个0,现在他要构造出一个长度为n的01序列,请问他有多少种不同的构造方法

这个数字可能会非常大,请你对109+7取模

输入格式

一行,给出两个整数n,k

输出格式

一个整数,代表不同的构造方法数

数据范围

1≤n≤10^6

0≤k<n

本题是一道非常基础的动态规划题,状态转移方程为

dp[i] += dp[i - 1];//如果新加的位置为0
        dp[i] %= M;
        if (i - k - 1 >= 1)//如果新加的位置为1
            dp[i] += dp[i - k - 1];
        else
            dp[i] += 1;
        dp[i] %= M;

知道了状态转移方程后,本题就解决了

#include <iostream>
using namespace std;
const int N = 1e6 + 5, M = 1e9 + 7;
int dp[N], k, n;
int main()
{
	cin >> n>>k;
	dp[1] = 2;
	for (int i = 2; i <= n; i++)
	{
		dp[i] += dp[i - 1];
		dp[i] %= M;
		if (i - k - 1 >= 1)
			dp[i] += dp[i - k - 1];
		else
			dp[i] += 1;
		dp[i] %= M;
	}
	cout << dp[n];

}

8.

约翰想要在他的正方形农场上建造一座正方形大牛棚。他讨厌在他的农场中砍树,想找一个能够让他在空旷无树的地方修建牛棚的地方。我们假定,他的农场划分成 n * n的方格。输入数据中包括有树的方格的列表。你的任务是计算并输出,在他的农场中,不需要砍树却能够修建的最大正方形牛棚。牛棚的边必须和水平轴或者垂直轴平行。 考虑下面的方格,它表示农夫约翰的农场,‘.'表示没有树的方格,‘#'表示有树的方格

........
.#...#..
........
........
........
..#.....
........
........

那么最大的牛棚是5*5的。

输入描述

第一行输入一个正整数 n(1≤n≤1000)代表农场的大小,一个正整数T(1≤T≤n∗n), 接下来 T 行,每行2个整数,代表有树的格子的横纵坐标,保证任意两个树格子不相同

输出描述

输出一个正整数代表牛棚的最大边长

本题也是一道比较基础的动态规划题,状态转移方程为

  if(map[i][j])
            {
                dp[i][j] = min(min(dp[i-1][j],dp[i][j-1]),dp[i-1][j-1])+1;
            }
            maxx = max(maxx,dp[i][j]);

知道了状态转移方程后,本题就比较简单了

#include<bits/stdc++.h>
using namespace std;
 
int n,m,map[1010][1010];
int dp[1010][1010];
 
int main()
{
    cin >> n >> m;

    for(int i = 1;i <= m;++i)
    {
        int x,y;
        cin >> x >> y;
        map[x][y] = 1;
    }
 
    int maxx = -1;
 
    for(int i = 1;i <= n;++i)
    {
        for(int j = 1;j <= n;++j)
        {
            if(!map[i][j])
            {
                dp[i][j] = min(min(dp[i-1][j],dp[i][j-1]),dp[i-1][j-1])+1;
            }
            maxx = max(maxx,dp[i][j]);
        }
    }
 
    cout << maxx;
 
    return 0;
}

9.

给定一个完全由小写英文字母组成的字符串等差递增序列,该序列中的每个字符串的长度固定为 L,从 L 个 a 开始,以 11 为步长递增。例如当 L 为 33时,序列为 aaa,aab,aac,...,aaz,aba,abb,...,abz,...,zzz。这个序列的倒数第 22 个字符串就是 zzy。对于任意给定的 L,本题要求你给出对应序列倒数第 N 个字符串。

输入格式

输入在一行中给出两个正整数 L(1≤L≤6和 N( N≤10^5). 注意:数据范围有修改!!!

输出格式

在一行中输出对应序列倒数第 N 个字符串。题目保证这个字符串是存在的。

本题是一道比较简单的分析题,注意n=1时没有变动即可

#include <iostream>
using namespace std;
char a[7];
int main()
{
	for (int i = 1; i <= 6; i++)
		a[i] = 'z';
	int n, l;
	cin >> l >> n;
	n--;
	int f = n / 26;
	a[l] -= n% 26;

	int z = l;
	while (f)
	{
		z--;
		a[z] -= f % 26;
		f /= 26;
	}
	for (int i = 1; i <= l; i++)
	{

		cout << a[i];
	}
}

10.

桌子上从左到右放着 n个糖果。糖果从左到右编号,第 i 块糖果的重量为 wi。小明和小红要吃糖果。

小明从左边开始吃任意数量的糖果。(连续吃,不能跳过糖果)

小红从右边开始吃任意数量的糖果。(连续吃,不能跳过糖果)

当然,如果小明吃了某个糖果,小红就不能吃它(反之亦然)。

他们的目标是吃同样重量的糖果,请问此时他们总共最多能吃多少个糖果?

这题的意思就是,两个人一个从左往右吃糖果,一个从右往左吃糖果,他们俩人吃的糖果重量要一样,问他们两人最多可以吃多少糖果。其实就是说,从左往右的连续和从右往左的连续和相等的情况下,这两个连续和一共用了多少个数(数量小于等于n)。

那么我们用两个数p,q表示小明和小红各吃了几个即可

#include <iostream>
using namespace std;
const int N = 2e5 + 5;
int n, x, y, z, p, q, a[N],ans;
int main()
{
	cin >> n;
	for (int i = 1; i <= n; i++)
		cin >> a[i];
	p = 1;
	q = 1;
	x += a[1];
	y += a[n];
	while (p + q <= n)
	{
		if (x==y)
			ans = p + q;
		if (x > y)
		{
			q++;
			y += a[n - q + 1];
		}
		else if (y > x)
		{
			p++;
			x+=a[p];
		}
		else
		{
			p++;
			q++;
			x += a[p];
			y += a[n - q + 1];
		}
	}
		cout << ans;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值