一道奇怪的题

今天reflash给我出了一道题:
ki=1xi[xi1][ki=1xiS]modpk,S1018,p107
我一开始是这样想的:如果 F(x)=i=0ixi ,那么答案就是 Fk(x) 的前S项系数和,所以我们就得到了一个 O(SlogSlogk) 的fft做法。。。
然后我就想能不能用别的方法做。。但是我发现如果我直接考虑这个式子我似乎只有dp的做法,而dp的话状态数首先就是 O(n2) 的,优化似乎也最多只能用fft了。。因为这个乘法它没法用分配律什么的提出来。
所以考虑模型转化,乘法可以看做是(1+1+1+…)(1+1+1+….)(1+1+1+…)…,所以就相当于是有S个球,我们把要把它们分成k份,再在每一份中选一个球。所以我们从左往右考虑,就相当于是要选一个球,再选一个球作为边界,再选一个球,再选一个边界。。但是问题在于,每一份中选的那个球和边界可以是同一个球。
所以我就不会做了。
然后听了reflash的讲解,感觉非常非常神奇!原来可以为每个边界单独开一个球, 就相当于是在S+k个球中选2k个球,然后从小到大排序把第偶数个球实际上是它左边的球,这样答案就是 C2kS+k

所以不妨再来看那个经典问题:在n个不同元素中有重复取k个的方案数。原来学的都是插板法,但是这样的话就可以得到一种更简单的解释了!对于每一种方案,我们选的元素编号更大的k-1个新建一个球;那么每一种在n+k-1个球中选k的方案,我们如果把后k-1个看成0,其他的n个看成1,那么选的这k个就等价于在选它或它左边第一个1,所以就与在n个元素中有重复取k个的方案一一对应。

广义地看这个问题,就是一个序列 {xn},xi[1,S],i[1,n],xixi10,i(1,n] ,其中有n-m个数要求 [i=1][xixi1>0] ,那么答案就是 CnS+m

以下是一道ACM目的示例: 目描述 给定一个整数数组和一个目标值,找出数组和为目标值的两个数。 你可以假设每个输入只对应一种答案,且同样的元素不能重复使用。 示例 给定 nums = [2, 7, 11, 15], target = 9 因为 nums[0] + nums[1] = 2 + 7 = 9 所以返回 [0, 1] 解思路 这道可以使用哈希表来解决。哈希表存储每个数的下标,遍历数组时,判断哈希表是否存在 target-nums[i],如果存在,则说明找到了符合要求的两个数,返回它们的下标即可。 代码实现 C++代码实现: ```cpp #include <iostream> #include <vector> #include <unordered_map> using namespace std; vector<int> twoSum(vector<int>& nums, int target) { unordered_map<int, int> m; for (int i = 0; i < nums.size(); i++) { int complement = target - nums[i]; if (m.count(complement)) { return {m[complement], i}; } m[nums[i]] = i; } return {}; } int main() { vector<int> nums = {2, 7, 11, 15}; int target = 9; vector<int> res = twoSum(nums, target); for (int i = 0; i < res.size(); i++) { cout << res[i] << " "; } return 0; } ``` Python代码实现: ```python def twoSum(nums, target): d = {} for i, n in enumerate(nums): complement = target - n if complement in d: return [d[complement], i] d[n] = i return [] nums = [2, 7, 11, 15] target = 9 print(twoSum(nums, target)) ``` Java代码实现: ```java import java.util.HashMap; public class Solution { public int[] twoSum(int[] nums, int target) { HashMap<Integer, Integer> map = new HashMap<>(); for (int i = 0; i < nums.length; i++) { int complement = target - nums[i]; if (map.containsKey(complement)) { return new int[] {map.get(complement), i}; } map.put(nums[i], i); } return new int[] {}; } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值