D. Love-Hate

思路:

n的范围是比较大的,某个人不在答案中概率为1/2,我们考虑随机去选取50个人,那么这50个人都不在答案中的概率为\(1/2^{50}\),概率是十分小,那么也就是随机选取50次后,会有其中一些人是包含答案的一个较大子集。

这里解释一下这道题定义的子集,比如1010有四个子集
分别为 1010 0101 1000 0100

即当前位为1的可变换为 1或 0, 如果当前位为0 ,则无需变换

我们随机选了一个人后,那我们考虑去枚举这个人所包含的子集,假如有k个1 那么就有\(2^k\)个子集,然后我们去看其他人对这些子集的包含程度如何,题目要求的是包含程度最高(即更多的1)

\(dp[i]=x\)表示有x个人的选项中包含 集合j

考虑如何进行dp:

假设随机被选中的人叫阿亮

dp初始化:

对于这n个人都有自己01串,

对于第i个人

我们要去找个一个最大的子集sum,sum满足既被阿亮包含又被 i 包含,那么这个子集sum需要加一,因为被他自己包含了

转移:

对于两个集合,1110 1100,我们不难得出,只要能够包含1110 那么必定也能够包含1100,因为后者的集合范围较小。

那我们考虑从大集合转移到小集合

vector bit 已经把随机选中的那个人的所有1的位置存了下来,最多也就15位

那么可以去枚举这些位置1的选择情况然后进行转移。

最终答案通过遍历所有的子集进行一个更新

(好像懵懵懂懂的,语言组织的不是很好,

codeforces上对sosdp的讲解:https://codeforces.com/blog/entry/45223

电音的视频讲解:https://www.bilibili.com/video/BV1L64y1R75n?spm_id_from=333.337.search-card.all.click

#include<bits/stdc++.h>
#define deb cout<<"--"<<endl;
#define int long long 
#define ll long long 
#define endl '\n'
using namespace std;
const int N=1e6+5;
const int inf=0x3f3f3f3f3f3f;
int a[N];
int n,m,p;
vector<int>bit,ans;
int dp[N];
void solve(){
    cin>>n>>m>>p;
    for(int i=1;i<=n;i++){
        string s;cin>>s;
        for(int j=0;j<m;j++){
            if(s[m-j-1]=='1'){
                a[i]+=(1ll<<j);
            }
        }
    }
    srand(time(0)*time(0));
    for(int k=1;k<=50;k++){
        int index=1ll*rand()*rand()%n+1;
        bit.clear();
        for(int j=0;j<m;j++){
            if((1ll<<j)&a[index]){
                bit.push_back(j);
            }
        }
        
        //dp的初始化
        memset(dp,0,sizeof(dp));
        for(int j=1;j<=n;j++){
            int sum=0;
            for(int i=0;i<bit.size();i++){
                if((1ll<<bit[i])&a[j]){
                    sum+=(1ll<<i);
                }
            }
            dp[sum]++;   //sum是a[j]的一个子集
        }
        //sosdp  
        
        for(int i=0;i<bit.size();i++){
            for(int j=0;j<=(1ll<<bit.size());j++){
                if((j&(1ll<<i))==0){
                    //这里==0的原因是,我们要转移到一个包含程度较小的,那也就是这一位为0,这个数1的位数越少,就会有更多·				
               	    //的人包含他
                    dp[j]+=dp[j+(1ll<<i)];
                }
            }
        }
        
        
        //去遍历所有可能的子集,看哪一个子集被更多的人包含,然后更新
        for(int i=0;i<(1<<15);i++){
            if(dp[i]>=(n+1)/2&&__builtin_popcount(i)>ans.size()){
                ans.clear();
                for(int j=0;j<m;j++){
                    if(i&(1ll<<j))ans.push_back(bit[j]);
                }
            }
        }
        
    }
    // cout<<ans.size()<<endl;
    string ens=string(m,'0');
        for(auto i:ans){
            ens[m-i-1]='1';
        }
        cout<<ens<<endl;
}
signed main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); 
	int kase=1;
    // cin>>kase;
    for(int i=1;i<=kase;i++){solve();}
}
 
posted @ 2022-04-28 17:10  LiAnG24  阅读(49)  评论(0)    收藏  举报