大家好,欢迎来到IT知识分享网。
目录
一,算两次
算两次是指,对同一个组合计数,算出2个不同的表达式,从而推导出2个表达式相等。
1,多对多匹配问题
2,平面剖分问题
3,多重计数问题
4,等价个体互换
力扣 1503. 所有蚂蚁掉下来前的最后一刻
有一块木板,长度为 n 个 单位 。一些蚂蚁在木板上移动,每只蚂蚁都以 每秒一个单位 的速度移动。其中,一部分蚂蚁向 左 移动,其他蚂蚁向 右 移动。
当两只向 不同 方向移动的蚂蚁在某个点相遇时,它们会同时改变移动方向并继续移动。假设更改方向不会花费任何额外时间。
而当蚂蚁在某一时刻 t 到达木板的一端时,它立即从木板上掉下来。
给你一个整数 n 和两个整数数组 left 以及 right 。两个数组分别标识向左或者向右移动的蚂蚁在 t = 0 时的位置。请你返回最后一只蚂蚁从木板上掉下来的时刻。
示例 1:
提示:
class Solution { public: int getLastMoment(int n, vector<int>& left, vector<int>& right) { int ans = 0; for (int i = 0; i < left.size(); i++)ans = max(ans, left[i]); for (int i = 0; i < right.size(); i++)ans = max(ans, n-right[i]); return ans; } };
力扣 2731. 移动机器人
有一些机器人分布在一条无限长的数轴上,他们初始坐标用一个下标从 0 开始的整数数组 nums
表示。当你给机器人下达命令时,它们以每秒钟一单位的速度开始移动。
给你一个字符串 s
,每个字符按顺序分别表示每个机器人移动的方向。'L'
表示机器人往左或者数轴的负方向移动,'R'
表示机器人往右或者数轴的正方向移动。
当两个机器人相撞时,它们开始沿着原本相反的方向移动。
请你返回指令重复执行 d
秒后,所有机器人之间两两距离之和。由于答案可能很大,请你将答案对 109 + 7
取余后返回。
注意:
- 对于坐标在
i
和j
的两个机器人,(i,j)
和(j,i)
视为相同的坐标对。也就是说,机器人视为无差别的。 - 当机器人相撞时,它们 立即改变 它们的前进方向,这个过程不消耗任何时间。
- 当两个机器人在同一时刻占据相同的位置时,就会相撞。
- 例如,如果一个机器人位于位置 0 并往右移动,另一个机器人位于位置 2 并往左移动,下一秒,它们都将占据位置 1,并改变方向。再下一秒钟后,第一个机器人位于位置 0 并往左移动,而另一个机器人位于位置 2 并往右移动。
- 例如,如果一个机器人位于位置 0 并往右移动,另一个机器人位于位置 1 并往左移动,下一秒,第一个机器人位于位置 0 并往左行驶,而另一个机器人位于位置 1 并往右移动。
示例 1:
输入:nums = [-2,0,2], s = "RLL", d = 3 输出:8 解释: 1 秒后,机器人的位置为 [-1,-1,1] 。现在下标为 0 的机器人开始往左移动,下标为 1 的机器人开始往右移动。 2 秒后,机器人的位置为 [-2,0,0] 。现在下标为 1 的机器人开始往左移动,下标为 2 的机器人开始往右移动。 3 秒后,机器人的位置为 [-3,-1,1] 。 下标为 0 和 1 的机器人之间距离为 abs(-3 - (-1)) = 2 。 下标为 0 和 2 的机器人之间的距离为 abs(-3 - 1) = 4 。 下标为 1 和 2 的机器人之间的距离为 abs(-1 - 1) = 2 。 所有机器人对之间的总距离为 2 + 4 + 2 = 8 。
示例 2:
输入:nums = [1,0], s = "RL", d = 2 输出:5 解释: 1 秒后,机器人的位置为 [2,-1] 。 2 秒后,机器人的位置为 [3,-2] 。 两个机器人的距离为 abs(-2 - 3) = 5 。
提示:
2 <= nums.length <= 105
-2 * 109 <= nums[i] <= 2 * 109
0 <= d <= 109
nums.length == s.length
s
只包含'L'
和'R'
。nums[i]
互不相同。
class Solution { public: int sumDistance(vector<int>& nums, string s, int d) { for(int i=0;i<s.length();i++)if(s[i]=='R')nums[i]+=d;else nums[i]-=d; sort(nums.begin(),nums.end()); long long ans=0; for(int i=1;i<nums.size();i++) ans+=((long long)nums[i]-nums[i-1])*i%*(nums.size()-i)%; return ans%; } };
二,贡献法
贡献法其实也蕴含了算两次的思想。
场景:要求若干项数据的和,而每个数据又可以分解成一些原子数据的和,那么就可以通过求每个原子数据在最终总和中的贡献,从而求出最终总和。
贡献法往往用于,若干项数据不太好求,但原子数据在最终总和中的贡献比较好求的场景。
CSU 1799 小Z的黑白棋
题目:
小Z有一些黑白棋,他觉得黑白混杂在一起极具美感,所以他总喜欢将这些棋子排成一排序列S1,但是小Y就喜欢跟小Z作对,她会趁小Z不注意偷偷将小Z最右边的棋子拿走,往他棋子序列的最左边添加一个白色的棋子形成一个新的序列S2来破坏小Z的美感。
S2(1~n) = 白棋+S1(i=1~n-1)
小Z总相信第一感,他认为他自己最初排好的序列S1是最完美的,新的序列S2会造成一定的破坏美感指数 = damage(S1) = S1与S2有多少个位置黑色与白色互不对应
Exp:
令白棋为a,黑棋为b :S1 = ababa S2=aabab damage(S1)=4
因为小Z有很多种摆放序列的方式,现在他希望让你帮他求所有摆放序列的方式会造成的damage(S1)的平均值
Input
多组数据输入输出
每组数据输入一个整数n和m表示白棋和黑棋的数量 0<=n , m<=1000,000,000 , 保证n+m>=1
Output
每组输出一个平均值答案,用最简分数表示,如果可以化简到整数,就用整数表示
Sample Input
3/2
这个题目的思想大约就是富比尼原理了。
n个白棋和m个黑棋有C(m+n,n)种排列。
其中,第一个棋子为黑棋的,有C(m+n-1,n)种
第i(i=1,2,3……m+n-1)个棋子和第i+1个棋子颜色不同的,有2*C(m+n-2,n-1)种
2*C(m+n-2,n-1)*(m+n-1)=2*n*C(m+n-1,n)
所以,本题答案是(1+2*n)*C(m+n-1,n)/C(m+n,n)=(1+2*n)*m/(m+n)
#include<iostream> #include<stdio.h> using namespace std; long long gcd(long long a,long long b) { if(b==0)return a; return gcd(b,a%b); } int main() { int m,n; long long a,b; while(scanf("%d%d",&n,&m)!=EOF) { a=n+n+1; a*=m; b=m+n; if(a%b==0)printf("%d\n",a/b); else cout<<a/gcd(a,b)<<'/'<<b/gcd(a,b)<<endl; } return 0; }
力扣 1863. 找出所有子集的异或总和再求和
一个数组的 异或总和 定义为数组中所有元素按位 XOR
的结果;如果数组为 空 ,则异或总和为 0
。
- 例如,数组
[2,5,6]
的 异或总和 为2 XOR 5 XOR 6 = 1
。
给你一个数组 nums
,请你求出 nums
中每个 子集 的 异或总和 ,计算并返回这些值相加之 和 。
注意:在本题中,元素 相同 的不同子集应 多次 计数。
数组 a
是数组 b
的一个 子集 的前提条件是:从 b
删除几个(也可能不删除)元素能够得到 a
。
示例 1:
输入:nums = [1,3] 输出:6 解释:[1,3] 共有 4 个子集: - 空子集的异或总和是 0 。 - [1] 的异或总和为 1 。 - [3] 的异或总和为 3 。 - [1,3] 的异或总和为 1 XOR 3 = 2 。 0 + 1 + 3 + 2 = 6
示例 2:
输入:nums = [5,1,6] 输出:28 解释:[5,1,6] 共有 8 个子集: - 空子集的异或总和是 0 。 - [5] 的异或总和为 5 。 - [1] 的异或总和为 1 。 - [6] 的异或总和为 6 。 - [5,1] 的异或总和为 5 XOR 1 = 4 。 - [5,6] 的异或总和为 5 XOR 6 = 3 。 - [1,6] 的异或总和为 1 XOR 6 = 7 。 - [5,1,6] 的异或总和为 5 XOR 1 XOR 6 = 2 。 0 + 5 + 1 + 6 + 4 + 3 + 7 + 2 = 28
示例 3:
输入:nums = [3,4,5,6,7,8] 输出:480 解释:每个子集的全部异或总和值之和为 480 。
提示:
1 <= nums.length <= 12
1 <= nums[i] <= 20
思路一:枚举
template<typename T> vector<vector<T>> getAllsubStes(const vector<T>&v) //生成2^n个子集,仅限n<=30的场景 { vector<vector<T>>ans; for (int i = (1 << v.size()) - 1; i >= 0; i--) { vector<int>t; for (int j = 0; j < v.size(); j++)if (i&(1 << j))t.push_back(v[j]); ans.push_back(t); } return ans; } class Solution { public: int subsetXORSum(vector<int>& nums) { vector<vector<int>>v = getAllsubStes(nums); int ans = 0; for (auto &vi : v) { int t = 0; for (auto x : vi)t ^= x; ans += t; } return ans; } };
思路二:
利用组合数学的贡献法,考虑每一位的1在最终结果中的贡献,计算结果是贡献次数要么等于固定值1<< nums.size() – 1,要么等于0。
class Solution { public: int subsetXORSum(vector<int>& nums) { int ans = 0; for (auto x : nums)ans |= x; return ans << nums.size() - 1; } };
力扣 2527. 查询数组 Xor 美丽值
给你一个下标从 0 开始的整数数组 nums
。
三个下标 i
,j
和 k
的 有效值 定义为 ((nums[i] | nums[j]) & nums[k])
。
一个数组的 xor 美丽值 是数组中所有满足 0 <= i, j, k < n
的三元组 (i, j, k)
的 有效值 的异或结果。
请你返回 nums
的 xor 美丽值。
注意:
val1 | val2
是val1
和val2
的按位或。val1 & val2
是val1
和val2
的按位与。
示例 1:
输入:nums = [1,4] 输出:5 解释: 三元组和它们对应的有效值如下: - (0,0,0) 有效值为 ((1 | 1) & 1) = 1 - (0,0,1) 有效值为 ((1 | 1) & 4) = 0 - (0,1,0) 有效值为 ((1 | 4) & 1) = 1 - (0,1,1) 有效值为 ((1 | 4) & 4) = 4 - (1,0,0) 有效值为 ((4 | 1) & 1) = 1 - (1,0,1) 有效值为 ((4 | 1) & 4) = 4 - (1,1,0) 有效值为 ((4 | 4) & 1) = 0 - (1,1,1) 有效值为 ((4 | 4) & 4) = 4 数组的 xor 美丽值为所有有效值的按位异或 1 ^ 0 ^ 1 ^ 4 ^ 1 ^ 4 ^ 0 ^ 4 = 5 。
示例 2:
输入:nums = [15,45,20,2,34,35,5,44,32,30] 输出:34 解释:数组的 xor 美丽值为 34 。
提示:
1 <= nums.length <= 105
1 <= nums[i] <= 109
思路:
利用组合数学的贡献法,考虑每一位的1在最终结果中的贡献,显然贡献次数要么等于1,要么等于0,经过计算,这只取决于所有数中该位的1的数目的奇偶性。
class Solution { public: int xorBeauty(vector<int>& nums) { int ans = 0; for (int i = 0; i < 30; i++) { int n = 0; for (auto x : nums)n += ((x >> i) & 1); if (n &1)ans += 1 << i; } return ans; } };
力扣 1835. 所有数对按位与结果的异或和
列表的 异或和(XOR sum)指对所有元素进行按位 XOR
运算的结果。如果列表中仅有一个元素,那么其 异或和 就等于该元素。
- 例如,
[1,2,3,4]
的 异或和 等于1 XOR 2 XOR 3 XOR 4 = 4
,而[3]
的 异或和 等于3
。
给你两个下标 从 0 开始 计数的数组 arr1
和 arr2
,两数组均由非负整数组成。
根据每个 (i, j)
数对,构造一个由 arr1[i] AND arr2[j]
(按位 AND
运算)结果组成的列表。其中 0 <= i < arr1.length
且 0 <= j < arr2.length
。
返回上述列表的 异或和 。
示例 1:
输入:arr1 = [1,2,3], arr2 = [6,5] 输出:0 解释:列表 = [1 AND 6, 1 AND 5, 2 AND 6, 2 AND 5, 3 AND 6, 3 AND 5] = [0,1,2,0,2,1] , 异或和 = 0 XOR 1 XOR 2 XOR 0 XOR 2 XOR 1 = 0 。
示例 2:
输入:arr1 = [12], arr2 = [4] 输出:4 解释:列表 = [12 AND 4] = [4] ,异或和 = 4 。
提示:
1 <= arr1.length, arr2.length <= 105
0 <= arr1[i], arr2[j] <= 109
利用组合数学的贡献法,考虑每一位的1在最终结果中的贡献。
class Solution { public: int getXORSum(vector<int>& arr1, vector<int>& arr2) { int s1=0,s2=0; for(auto x:arr1)s1^=x; for(auto x:arr2)s2^=x; return s1&s2; } };
力扣 477. 汉明距离总和
两个整数的 汉明距离 指的是这两个数字的二进制数对应位不同的数量。
给你一个整数数组 nums
,请你计算并返回 nums
中任意两个数之间 汉明距离的总和 。
示例 1:
输入:nums = [4,14,2] 输出:6 解释:在二进制表示中,4 表示为 0100 ,14 表示为 1110 ,2表示为 0010 。(这样表示是为了体现后四位之间关系) 所以答案为: HammingDistance(4, 14) + HammingDistance(4, 2) + HammingDistance(14, 2) = 2 + 2 + 2 = 6
示例 2:
输入:nums = [4,14,4] 输出:4
提示:
1 <= nums.length <= 104
0 <= nums[i] <= 109
- 给定输入的对应答案符合 32-bit 整数范围
class Solution { public: int totalHammingDistance(vector<int>& nums) { int mi = 1, ans = 0; for (int i = 0; i < 31; i++) { int num[2] = { 0,0 }; for (auto x : nums)num[((x&mi) > 0)]++; ans += num[0] * num[1]; mi <<= 1; } return ans; } };
力扣 2063. 所有子字符串中的元音
给你一个字符串 word
,返回 word
的所有子字符串中 元音的总数 ,元音是指 'a'
、'e'
、'i'
、'o'
和 'u'
。
子字符串 是字符串中一个连续(非空)的字符序列。
注意:由于对 word
长度的限制比较宽松,答案可能超过有符号 32 位整数的范围。计算时需当心。
示例 1:
输入:word = "aba" 输出:6 解释: 所有子字符串是:"a"、"ab"、"aba"、"b"、"ba" 和 "a" 。 - "b" 中有 0 个元音 - "a"、"ab"、"ba" 和 "a" 每个都有 1 个元音 - "aba" 中有 2 个元音 因此,元音总数 = 0 + 1 + 1 + 1 + 1 + 2 = 6 。
示例 2:
输入:word = "abc" 输出:3 解释: 所有子字符串是:"a"、"ab"、"abc"、"b"、"bc" 和 "c" 。 - "a"、"ab" 和 "abc" 每个都有 1 个元音 - "b"、"bc" 和 "c" 每个都有 0 个元音 因此,元音总数 = 1 + 1 + 1 + 0 + 0 + 0 = 3 。
示例 3:
输入:word = "ltcd" 输出:0 解释:"ltcd" 的子字符串均不含元音。
示例 4:
输入:word = "noosabasboosa" 输出:237 解释:所有子字符串中共有 237 个元音。
提示:
1 <= word.length <= 105
word
由小写英文字母组成
class Solution { public: long long countVowels(string word) { long long ans = 0, len = word.length(); for (int i = 0; i < len; i++) { if (word[i] == 'a' || word[i] == 'e' || word[i] == 'i' || word[i] == 'o' || word[i] == 'u')ans += i * (len - 1 - i) + len; } return ans; } };
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/123110.html