第 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];
}
};