老师为即将毕业的同学们准备了一场舞会,有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;
}