【数位贪心】

【数位贪心】

十进制/二进制填数字
一般是从高位到低位考虑->继承

Minimum OR Path

https://atcoder.jp/contests/abc408/tasks/abc408_e

/*【贪心】最高位为0,次高位为0,...->从高位扫到低位 并继承高位的结果
【位数】设S:S中若存在i:所存在的边,第i位一定全是0
->从高位到低位:继承上一次的S,并把当位设成1(满足条件)
->如果能跑到n:说明该位是可以的 否则ans该位设为1
*/
const int N=2e5+10;
int n,m;
vector<PII> g[N];
bool st[N];
void dfs(int u,int fa,int x){
    st[u]=1;
    for(auto son:g[u]){
        int pos=son.first;
        int val=son.second;
        if(pos!=fa){       //该位及以前继承的位全为0
            if(!st[pos] && !(val&x)) dfs(pos,u,x);
        }
    }
}
void solve(){
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        int u,v,w;
        cin>>u>>v>>w;
        g[u].push_back({v,w});
        g[v].push_back({u,w});
    }
    int s=0,ans=0;
    for(int i=29;i>=0;i--){
        memset(st,0,sizeof st);
        dfs(1,-1,s|(1<<i));
        if(st[n]) s|=(1<<i);
        else ans|=(1<<i);
    }
    cout<<ans<<endl;
}

XOR-factorization

【经典二进制填数trick】
https://codeforces.com/contest/2180/problem/C

题目大意

给定n和k,满足\(0<=a_i<=n\),需要使得\(a_1⊕a_2⊕...⊕a_k=n\),且要使\(a_1+a_2+...+a_k=n\)最大,求序列。

思路

在可以的范围内构造尽可能多的1
若n为奇数:全部为n即可
若n为偶数
错误贪心思路:前n-2个数全为n 第n-1和n个数拼成一个n

正确思路: 按位考虑
image
b946e5cbcf2b6d3826282c98c5584f1b_720

代码

i64 n;
int k;
void solve(){
    cin>>n>>k;
    if(k%2){
        for(int i=1;i<=k;i++){
            cout<<n<<" ";
        }
        cout<<endl;
    }
    else{
        vector<i64> ans(k+1,0);
        int idx=0,c=1;
        for(i64 i=60;i>=0;i--){
            if((n>>i)&1LL){
                for(int j=1;j<=k;j++){
                    if(j!=c){
                        ans[j]+=(1LL<<i);
                    }
                }
                c=(c+1)%k;
                if(c==0) c=k;
                idx++;
            }
            else{
                for(int j=1;j<=idx/2*2&&j<=k;j++){
                    ans[j]+=(1LL<<i);
                }
            }
        }
        for(int i=1;i<=k;i++) cout<<ans[i]<<" ";
        cout<<endl;
    }
}
posted @ 2025-06-01 23:02  White_ink  阅读(13)  评论(0)    收藏  举报