• 数位 dp trick


    CF1290F Making Shapes

    考虑凸包,向量集合确定了就能确定唯一凸包。

    考虑向量加法转化到最后就是 \(\sum_{x_i>0}c_ix_i=-\sum_{x_i<0}c_ix_i,\sum_{y_i>0}c_iy_i=-\sum_{y_i<0}c_iy_i,\sum_{x_i>0}c_ix_i\le m,\sum_{y_i>0}c_iy_i \le m\)

    这里 trick 就是用数位 dp 的方式去解决 c 的方案。

    先考虑在 10 进制下怎么做?

    因为有进位,意味着我们要从低位到高位确定 \(c_i\),假如当前到了第 \(pos\) 位,那么从 \([0,9]\) 枚举,然后使得其符合条件(每一位都要满足当前位的 \(\sum_{x_i>0}c_ix_i=-\sum_{x_i<0}c_ix_i,\sum_{y_i>0}c_iy_i=-\sum_{y_i<0}c_iy_i\) ,做类似十进制下的加法运算(维护每一个 \(sum\) 的进位)即可。

    更优地,即在二进制下做加法。

    #include <bits/stdc++.h>
    #define int long long
    #define pb push_back
    using namespace std;
    const int mod=998244353;
    int n,m,a[6],b[6],xgf[100002][6],tot,NW[6];
    int f[10][23][23][23][23][2][2];
    
    int get(int x,int y) {
    	while(y) x/=10,--y; return x%10;
    }
    
    bool check(int x,int y,bool fl) {
    	if(x!=y) return x<y?0:1;
    	return fl;
    }
    
    int dfs(int pos,int sum1,int sum2,int sum3,int sum4,bool lim1,bool lim2) { //sum1 sum2 x 正 x 负 
    //	if(sum1) cout<<pos<<" "<<sum1<<" "<<sum2<<" "<<sum3<<" "<<sum4<<endl;
    	if(pos==10) return (!sum1&&!sum2&&!sum3&&!sum4&&!lim1&&!lim2);
    	if(~f[pos][sum1][sum2][sum3][sum4][lim1][lim2]) return f[pos][sum1][sum2][sum3][sum4][lim1][lim2];
    	int qwq=get(m,pos); 
    //	cout<<qwq<<endl;
    	f[pos][sum1][sum2][sum3][sum4][lim1][lim2]=0;
    	for(int i=1;i<=tot;i++) {
    		int res1=sum1,res2=sum2,res3=sum3,res4=sum4;
    		for(int j=1;j<=n;j++) {
    			if(a[j]>0) res1+=xgf[i][j]*a[j];
    			if(a[j]<0) res2-=xgf[i][j]*a[j];
    			if(b[j]>0) res3+=xgf[i][j]*b[j];
    			if(b[j]<0) res4-=xgf[i][j]*b[j];
    		}
    //		cout<<res1<<" "<<res2<<" : "<<res3<<" "<<res4<<endl;
    		if((res1%10)==(res2%10)&&(res3%10)==(res4%10)) {
    			f[pos][sum1][sum2][sum3][sum4][lim1][lim2]=(f[pos][sum1][sum2][sum3][sum4][lim1][lim2]+dfs(pos+1,res1/10,res2/10,res3/10,res4/10,check(res1%10,qwq,lim1),check(res3%10,qwq,lim2)))%mod;
    		}
    	}
    	return f[pos][sum1][sum2][sum3][sum4][lim1][lim2];
    }
    
    void init(int x) {
    	if(x==n+1) {
    		++tot; for(int i=1;i<=n;i++) xgf[tot][i]=NW[i];
    //		for(int i=1;i<=n;i++) cout<<NW[i]<<' ';
    //		cout<<'\n';
    		return ;
    	}
    	for(int i=0;i<=9;i++) NW[x]=i,init(x+1);
    }
    
    signed main() {
    //	cin.tie(0); ios::sync_with_stdio(false);
    	
    //	cout<<tot<<endl;
    	cin>>n>>m; init(1); memset(f,-1,sizeof(f));
    	for(int i=1;i<=n;i++) cin>>a[i]>>b[i];
    	cout<<(dfs(0,0,0,0,0,0,0)+mod-1)%mod;
    }
    
    #include <bits/stdc++.h>
    #define int long long
    #define pb push_back
    using namespace std;
    const int mod=998244353;
    int n,m,a[6],b[6];
    int f[31][21][21][21][21][2][2];
    
    bool check(int x,int y,bool fl) {
    	if(x!=y) return x<y?0:1;
    	return fl;
    }
    
    int dfs(int pos,int sum1,int sum2,int sum3,int sum4,bool lim1,bool lim2) { //sum1 sum2 x 正 x 负 
    //	if(sum1) cout<<pos<<" "<<sum1<<" "<<sum2<<" "<<sum3<<" "<<sum4<<endl;
    	if(pos==30) return (!sum1&&!sum2&&!sum3&&!sum4&&!lim1&&!lim2);
    	if(~f[pos][sum1][sum2][sum3][sum4][lim1][lim2]) return f[pos][sum1][sum2][sum3][sum4][lim1][lim2];
    	int qwq=(m>>pos)&1; 
    //	cout<<qwq<<endl;
    	f[pos][sum1][sum2][sum3][sum4][lim1][lim2]=0;
    	for(int S=0;S<(1<<n);S++) {
    		int res1=sum1,res2=sum2,res3=sum3,res4=sum4;
    		for(int j=1;j<=n;j++) {
    			int c=(S>>(j-1))&1;
    			if(a[j]>0) res1+=c*a[j];
    			if(a[j]<0) res2-=c*a[j];
    			if(b[j]>0) res3+=c*b[j];
    			if(b[j]<0) res4-=c*b[j];
    		}
    //		cout<<res1<<" "<<res2<<" : "<<res3<<" "<<res4<<endl;
    		if((res1&1)==(res2&1)&&(res3&1)==(res4&1)) {
    			f[pos][sum1][sum2][sum3][sum4][lim1][lim2]=(f[pos][sum1][sum2][sum3][sum4][lim1][lim2]+dfs(pos+1,res1>>1,res2>>1,res3>>1,res4>>1,check(res1&1,qwq,lim1),check(res3&1,qwq,lim2)))%mod;
    		}
    	}
    	return f[pos][sum1][sum2][sum3][sum4][lim1][lim2];
    }//er
    
    signed main() {
    	cin.tie(0); ios::sync_with_stdio(false);
    	cin>>n>>m; memset(f,-1,sizeof(f));
    	for(int i=1;i<=n;i++) cin>>a[i]>>b[i];
    	cout<<(dfs(0,0,0,0,0,0,0)+mod-1)%mod;
    }
    
    

    AT2272 [ARC066B] Xor Sum

    考虑 \((v,u),(a+b,a \bigotimes b),(2(a\&b)+a\bigotimes b,a\bigotimes b)\),显然我们有 \(a\&b=(v-u)/2\),且 \((a\&b)\& (a\bigotimes b)=0\),即 \(\dfrac{v-u}{2}\& u=0\)

    因为 \(v\ge u\),那么限制 \(v\) 做数位 dp 即可,\(v=2*\dfrac{v-u}{2}+u\),转移的时候让当前这一位的与为 0。

    #include <bits/stdc++.h>
    #define int long long
    #define pb push_back
    using namespace std;
    const int mod=(int)(1e9+7);
    int n,ans,f[62][100][2];
    
    bool check(int x,int y,bool fl) {
    	if(x^y) return x<y?0:1; return fl;
    }
    
    int dfs(int pos,int sum,bool lim) {
    	if(pos==62) return (!lim&&!sum); //没有达到上界且没有进位,因为这位必为 0 
    	if(~f[pos][sum][lim]) return f[pos][sum][lim];
    	int qwq=(n>>pos)&1;
    	f[pos][sum][lim]=(dfs(pos+1,sum>>1,check(sum&1,qwq,lim))+dfs(pos+1,(sum+1)>>1,check((sum+1)&1,qwq,lim))+dfs(pos+1,(sum+2)>>1,check((sum+2)&1,qwq,lim)))%mod;
    	return f[pos][sum][lim];
    }
    
    signed main() {
    	cin.tie(0); ios::sync_with_stdio(false);
    	cin>>n; memset(f,-1,sizeof(f));
    	cout<<dfs(0,0,0);
    }
    
  • 相关阅读:
    建立自己的开发知识库?分享制作电子书的经验
    海量Office文档搜索
    为什么要检测数据库连接是否可用
    多年的.NET开发,也只学会了这么几招
    总结一下ERP .NET程序员必须掌握的.NET技术
    菜单设计器(Menu Designer)及其B/S,C/S双重实现(B/S开源)
    软件公司为什么要加密源代码
    .NET开发中经常用到的扩展方法
    在Win8 Mertro 中使用SQLite
    SQLite
  • 原文地址:https://www.cnblogs.com/xugangfan/p/16218224.html
Copyright © 2020-2023  润新知