1. 程式人生 > >51nod 1301 集合異或和——異或dp

51nod 1301 集合異或和——異或dp

ace 不可 urn 異或和 size tdi ++ 一個 set

題目:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1301

好題!看了TJ才會。

因為是不可重集合,所以當然有前 i 個表示A和B都考慮的前 i 個,新加一個討論放A、放B、不放。

A<B在異或上看就是有一位,它前面的A和B都一樣,該位A是0、B是1。該位可以枚舉。然後就能dp了。

註意邊界細節……和標程對拍真愉快……

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using
namespace std; const int N=2005,M=4100,mod=1e9+7; int n,m,mi,mj,lm,dp[2][M][2],ans,bin[25]; int calc(int a) { int ret=0; while(a) a>>=1,ret++; return ret; } void ad(int &x,int y) { x=(x+y>=mod?x+y-mod:x+y); } int main() { scanf("%d%d",&n,&m); mi=max(n,m); lm=calc(m); int
tmp=calc(mi); bin[1]=1; for(int i=2;i<=tmp;i++) bin[i]=(bin[i-1]<<1);//tmp not lm!!! bin[tmp+1]=(bin[tmp]<<1); mj=bin[tmp+1]-1; for(int t=1;t<=lm;t++) { memset(dp[0],0,sizeof dp[0]);///not dp[0] if mj isn‘t gu ding dp[0][0][0]=1; // mj=1; for(int
i=1,u,v;i<=mi;i++) { u=(i&1);v=!u; // if(i>=bin[mj])mj++; // for(int j=0;j<=bin[mj];j++) for(int j=0;j<=mj;j++) { dp[u][j][0]=dp[v][j][0]; dp[u][j][1]=dp[v][j][1]; if(i<=n)//A { ad(dp[u][j][0],dp[v][j^i][0]); ad(dp[u][j][1],dp[v][j^i][1]); } if(i<=m)//B { bool d=(i&bin[t]); ad(dp[u][j][0],dp[v][j^i][0^d]); ad(dp[u][j][1],dp[v][j^i][1^d]); } } } int d=(mi&1);// mi not n!!! for(int i=bin[t];i<bin[t+1];i++) ad(ans,dp[d][i][1]); } printf("%d\n",ans); return 0; }

51nod 1301 集合異或和——異或dp