形如求某一数字的倍数的方案数的题

例题:https://ac.nowcoder.com/acm/contest/95928/D

题意简析:在数组中选取两个数 \(a_i ,a_j\),使得两数乘积为495的倍数,同时可以进行一次(仅一次)的操作:使某个\(a_i\)加1,求出最大方案数

思路:通常遇到这种题目,需要对目标数进行质因数分解,分解后可以采用二进制表达质因子,同时也可以用二进制来查找所需的质因子

//通过质因子分解,可将495分解为3,3,5,11
//因此可以用四位二进制位来表示这四个质因子

#include<bits/stdc++.h>
#define endl '\n'
#define lowbit(x) (x&-x)
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const double pi=acos(-1);

void solve(){
    int n;cin>>n;
    vector<int> a(n+1);
    
    for(int i=1;i<=n;i++) cin>>a[i];
    
	//二进制转换为标志数,用以确定当前已有/未有的因子
    auto cg=[](int x){
        int res=0;
        if(x%3==0) res|=1;
        if(x%9==0) res|=2;
        if(x%5==0) res|=4;
        if(x%11==0) res|=8;
        
        return res;
    };
    //已有/未有的因子判断
    auto ck=[&](int x,int y){
        return (x|y)==15 || ((x|y)==13 && x&1 && y&1);//后面表示缺少一个3的情况
    };
	
	//对于例题,可以先维护在没有修改状态下的所有方案
	//对于唯一一次修改,可以通过枚举数组+维护前后缀来快速求出修改后对方案数的影响
	
    ll ans=0;
    vector<int> val(n+1);
    vector pre(n+1,vector<int>(20)),suf(n+2,vector<int>(20));
	//维护前缀,同时求出无修方案数
    for(int i=1;i<=n;i++){
        int t=cg(a[i]);
        val[i]=t;
        for(int j=0;j<20;j++) if(ck(j,val[i])) ans+=pre[i-1][j];
        
        pre[i]=pre[i-1];
        pre[i][val[i]]++;
    }
    //维护后缀
    for(int i=n;i>=1;i--){
        suf[i]=suf[i+1];
        suf[i][val[i]]++;
    }
    ll mx=0;
	//枚举修改位置,通过前后缀求出最终方案数,同时求最大值
    for(int i=1;i<=n;i++){
        ll res=0;
        int t=a[i];
        t++;
        int tem=cg(t);
        for(int j=0;j<20;j++) if(ck(j,tem)) res+=pre[i-1][j];
        for(int j=0;j<20;j++) if(ck(j,tem)) res+=suf[i+1][j];
        
        for(int j=0;j<20;j++) if(ck(j,val[i])) res-=pre[i-1][j];
        for(int j=0;j<20;j++) if(ck(j,val[i])) res-=suf[i+1][j];
        
        mx=max(mx,res);
    }
    
    cout<<mx+ans<<endl;
}

signed main(){
    ios::sync_with_stdio(false);cin.tie(nullptr);
    int t=1;
    //cin>>t;
    while(t--) solve();
    return 0;
}


posted on 2024-11-25 22:00  TaopiTTT  阅读(2)  评论(0编辑  收藏  举报