第 218 场周赛
5620. 连接连续二进制数字
给你一个整数
n
,请你将
1
到
n
的二进制表示连接起来,并返回连接结果对应的 十进制 数字对
109 + 7
取余的结果。
- 怎么计算,从左往右,还是从右往左,类似于除法,从左往右比较好,方便处理取模运算
- 怎么进位,当i=2^x时,进一位;
const int mod=1e9+7;
int getFirstOne(int num){
bitset<32> bs(num);
int i = 31;
for (; i >=0; i--) {
if (bs[i]==1)
break;
}
return i+1;
}
int concatenatedBinary(int n) {
long long ans=0;
int cnt=1;
int rec=2;
for(int i=1;i<=n;i++){
if(rec==i){
cnt++;
rec*=2;
}
ans=(ans<<cnt)+i;
ans%=mod;
}
return (int) ans;
}
//用python也很简单
def concatenatedBinary(self, n: int) -> int:
ans=0
mod=10**9+7
for num in range(1,n+1):
b=bin(num)[2:];
cnt=len(b);
ans=(ans<<cnt)+num;
ans%=mod
return ans
5619. 最小不兼容性
给你一个整数数组 nums 和一个整数 k 。你需要将这个数组划分到 k 个相同大小的子集中,使得同一个子集里面没有两个相同的元素。
一个子集的 不兼容性 是该子集里面最大值和最小值的差。
请你返回将数组分成 k 个子集后,各子集 不兼容性 的 和 的 最小值 ,如果无法分成分成 k 个子集,返回 -1 。
子集的定义是数组中一些数字的集合,对数字顺序没有要求。
示例 1:
输入:nums = [1,2,1,4], k = 2
输出:4
解释:最优的分配是 [1,2] 和 [1,4] 。
不兼容性和为 (2-1) + (4-1) = 4 。
注意到 [1,1] 和 [2,4] 可以得到更小的和,但是第一个集合有 2 个相同的元素,所以不可行。
示例 2:
输入:nums = [6,3,8,1,3,1,2,2], k = 4
输出:6
解释:最优的子集分配为 [1,2],[2,3],[6,8] 和 [1,3] 。
不兼容性和为 (2-1) + (3-2) + (8-6) + (3-1) = 6 。
示例 3:
输入:nums = [5,3,3,6,3,3], k = 3
输出:-1
解释:没办法将这些数字分配到 3 个子集且满足每个子集里没有相同数字。
提示:
1 <= k <= nums.length <= 16
nums.length 能被 k 整除。
1 <= nums[i] <= nums.length
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-incompatibility
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
基本思路:使用dfs,但是要注意剪枝
int ans=INT_MAX;
int k;
int per;
void dfs(vector<int> &cur,vector<int> &cnt,int tmp,int step,vector<int> &nums){
if(tmp>ans)
return;
if(step==nums.size()){
ans=min(ans,tmp);
return ;
}
for(int i=0;i<k;i++){
if(nums[step]==cur[i]) //当前集合里有相同的数字,不能放
continue;
if(cnt[i]<per){ //集合没有满
int pre=cur[i];
cur[i]=nums[step];
cnt[i]++;
dfs(cur,cnt,tmp+((pre!=-1)?cur[i]-pre:0),step+1,nums);
cnt[i]--;
cur[i]=pre;
if(cnt[i]==0) //i以及i之后的集合都是空的,放那个里面都一样
break;
}
}
return ;
}
int minimumIncompatibility(vector<int>& nums, int k) {
unordered_map<int,int> dict;
int n=nums.size();
for(auto &it:nums){
dict[it]++;
if(dict[it]>k)
return -1;
}
sort(nums.begin(),nums.end());
vector<int> cur(k,-1);
vector<int> cnt(k,0);
this->k=k;
this->per=n/k;
dfs(cur,cnt,0,0,nums);
return ans;
}
基本思路:动态规划,先做预备工作,找到所有符合条件的小集合,然后筛选,其中,对于f[mask],mask表示的是二进制代码中为1的已经分配好集合了,而f[mask]表示的是最小兼容差
- if f[mask]=-1,f[mask]=f[mask^sub]+value[sub] ,表示的是f[mask]可以有sub集合,以及其补集组成
- if f[mask]=-1,f[mask]=min(f[mask],f[mask^sub]+value[sub]);
class Solution {
public:
int minimumIncompatibility(vector<int>& nums, int k) {
if(k==nums.size())
return 0;
unordered_map<int,int> dict;
for(auto &it:nums){
dict[it]++;
if(dict[it]>k)
return -1;
}
int n=nums.size();
int M=(1<<n);
vector<int> value(M,-1); //预备工作,找到所有的分组
vector<int> frequent(n+1,0);
for(int i=1;i<M;i++){
if(__builtin_popcount(i)==n/k){
for(int j=0;j<n;j++){
if(i&(1<<j)){
frequent[nums[j]]++;
}
}
bool flag=true;
for(int j=1;j<=n;j++){
if(frequent[j]>1){
flag=false;
break;
}
}
if(flag){
int lb=INT_MAX,ub=INT_MIN;
for(int j=1;j<=n;j++){
if(frequent[j]>0){
lb=min(lb,j);
ub=max(ub,j);
}
}
value[i]=ub-lb;
//cout<<i<<" "<<value[i]<<endl;
}
for(int j=0;j<n;j++){
if(i&(1<<j)){
--frequent[nums[j]];
}
}
}
}
vector<int> f(M,-1);
f[0]=0;
for(int mask=1;mask<M;++mask){
if(__builtin_popcount(mask)%(n/k)==0){
for(int sub=mask;sub;sub=(sub-1)&mask){
if(value[sub]!=-1&&f[mask^sub]!=-1){
if(f[mask]!=-1){
f[mask]=min(f[mask],f[mask^sub]+value[sub]);//mask^sub表示的是不含sub的其他集合
}
else{
f[mask]=f[mask^sub]+value[sub];
}
}
}
}
}
return f[M-1];
}
};