A
枚举x , 然后对于确定的x , 最后总的apple数对应了唯一的orange数,因此问题转化为求apple的取值范围;
apple的取值范围: max为每个bag取最多的apple , min为每个bag取最小的apple , 容易证明[min,max]是连续的.
1 using namespace std; 2 3 class WinterAndPresents { 4 public: 5 long long getNumber(vector <int>, vector <int>); 6 }; 7 struct node { 8 int a,o; 9 };vector<node> f; 10 bool cmp(node x,node y) { 11 if (x.a==y.a) return x.o<y.o; 12 return x.a<y.a; 13 } 14 long long WinterAndPresents::getNumber(vector <int> apple, vector <int> orange) { 15 long long ans = 0; 16 int x = -1,n = apple.size(); 17 for (int i=0 ; i<n ; i++ ) { 18 if (x==-1 || x>apple[i]+orange[i]) x=apple[i]+orange[i]; 19 f.push_back((node){apple[i],orange[i]}); 20 } 21 for (int i=1 ; i<=x ; i++ ) { 22 long long big = 0 , sml = 0; 23 for (int j=0 ; j<n ; j++ ) { 24 if (f[j].a>=i) big += i; 25 else big += f[j].a; 26 27 if (f[j].o>=i) sml += 0; 28 else sml += i-f[j].o; 29 } 30 ans += big-sml+1; 31 } 32 return ans; 33 }
B
关键在于优化dp状态.
朴素的dp是: dp[i][mask1][mask2] 在考虑第i个数时 集合1的状态为mask1 , 集合2的状态为mask2.
为了优化掉一维,应该考虑把状态设计成 dp[i][mask1^mask2] , 然后为了识别大小再用1维记录最高非0位属于哪个集合,
再换个角度来看,可以枚举最后最高非0位在位置p , 然后用dp[i][mask1^mask2][0/1]表示:
选择了i个 ; 集合1,2的异或值异或为mask1^mask2 ; mask1在p位置是0/1
就把原来的 O(maxn*mask1*mask2) 复杂度优化为O(maxn*mask1*2*log(maxn))
最后,在实现的时候可以把 (mask1^mask2) 右移p位 , 因为最高非零位之后的都无关紧要, 此时的状态数变更小了,用dfs实现可以更快.
1 #include <vector> 2 #include <list> 3 #include <map> 4 #include <set> 5 #include <deque> 6 #include <stack> 7 #include <bitset> 8 #include <algorithm> 9 #include <functional> 10 #include <numeric> 11 #include <utility> 12 #include <sstream> 13 #include <iostream> 14 #include <iomanip> 15 #include <cstdio> 16 #include <cmath> 17 #include <cstdlib> 18 #include <ctime> 19 #include <cstring> 20 using namespace std; 21 #define mod 1000000007 22 class WinterAndSnowmen { 23 public: 24 int getNumber(int, int); 25 }; 26 int dp[2001][1<<11][2],p,n,m; 27 int dfs(int t,int sum,int b) { 28 //printf("t:%d sum:%d b:%d\n",t,sum,b); 29 if (t==0) { 30 // printf("p:%d sum:%d b:%d\n",p,sum,b); 31 if ( sum==1 && b==0 ) return 1; 32 else return 0; 33 } 34 if (dp[t][sum][b]!=-1) return dp[t][sum][b]; 35 else { 36 long long res = 0; 37 if (t<=n) { 38 res += dfs( t-1 , sum^(t>>p) , b^((t>>p)&1) ); 39 } 40 if (t<=m) { 41 res += dfs(t-1 , sum^(t>>p) , b ); 42 } 43 res += dfs( t-1 , sum , b ); 44 res %= mod; 45 return dp[t][sum][b]=(int)res; 46 } 47 } 48 int WinterAndSnowmen::getNumber(int N, int M) { 49 int res = 0; 50 n = N , m = M; 51 for (int i=0 ; i<11 ; i++ ) { 52 memset(dp,-1,sizeof(dp)); 53 p = i; 54 res += dfs(max(N,M),0,0); 55 res %= mod; 56 // printf("i:%d add:%d\n",i,tmp); 57 } 58 return res; 59 } 60 61 62 //Powered by [KawigiEdit] 2.0!
C
又是个需要状态优化的dp.
朴素的状态设计是: f(t , r0 , g0 , b0 , r1 , g1 , b1) , 表示第t天 , 第一个shop的销售情况和第二个shop的销售情况;
但是考虑到两个shop同时营业时 , 销售情况必须一致 , 当碰到有同时营业的情况时 , 可以直接跳到下一个结束点:
于是新的状态表示为 f(t,r0,g0,b0) ;
然后再通过各种判断,来知道如何转移;
进一步优化是去掉b0的记录, 因为每天必须售出一个ball , 知道当前天t,开始天first,已经其它销售情况就能计算出b0.
最后的状态表示为f(t,r0,g0).
1 using namespace std; 2 #define maxn 510 3 #define mod 1000000007 4 class WinterAndShopping { 5 public: 6 int getNumber(vector <int>, vector <int>, vector <int>, vector <int>); 7 }; 8 9 struct node{ 10 int f,r,g,b; 11 int end() { 12 return f+r+g+b; 13 } 14 };vector<node> s[maxn]; 15 int dp[maxn][101][101],c[maxn][maxn]; 16 17 void pretreat(vector<int> f, vector<int> r, vector<int> g, vector<int> b) { 18 for (int i=0 ; i<(int)f.size() ; i++ ) { 19 for (int j=f[i] ; j<f[i]+r[i]+g[i]+b[i] ; j++ ) { 20 s[j].push_back((node){f[i],r[i],g[i],b[i]}); 21 } 22 } 23 for (int i=0 ; i<maxn ; i++ ) if (s[i].size()==2) { 24 if (s[i][0].f>s[i][1].f) swap(s[i][0],s[i][1]); 25 } 26 for (int i=0 ; i<maxn ; i++ ) { 27 c[i][0] = 1; 28 for (int j=1 ; j<=i ; j++ ) 29 c[i][j] = (c[i-1][j-1] + c[i-1][j]) % mod; 30 } 31 } 32 33 long long getfct(int r,int g,int b) { 34 long long res = (long long)c[r+g+b][r] * (long long )c[g+b][g] % mod; 35 // printf("r:%d g:%d b:%d res:%lld\n",r,g,b,res); 36 return res; 37 } 38 39 long long dfs(int t,int r,int g) { 40 if (t==501) { 41 if (r==0 && g==0) return 1; 42 else return 0; 43 } 44 if (dp[t][r][g]!=-1) return (long long)dp[t][r][g]; 45 else { 46 long long res = 0; 47 if (s[t].size()==0) res = dfs(t+1,0,0); 48 else if (s[t].size()==1) { 49 if (t+1 == s[t][0].end()) res = dfs(t+1,0,0); 50 else { 51 if (r+1<=s[t][0].r) res += dfs(t+1,r+1,g); 52 if (g+1<=s[t][0].g) res += dfs(t+1,r,g+1); 53 if (t-s[t][0].f-r-g+1<=s[t][0].b) res += dfs(t+1,r,g); 54 } 55 res %= mod; 56 } 57 else if (s[t].size()==2) { 58 node s0 = s[t][0] , s1 = s[t][1]; 59 int b = (t-s0.f-(r+g)); 60 if (s0.end() == s1.end()) { 61 if (s0.r-r==s1.r && s0.g-g==s1.g && s0.b-b==s1.b) { 62 res = getfct(s1.r,s1.g,s1.b) * dfs(s1.end(),0,0) % mod; 63 } 64 } else if (s0.end() < s1.end()) { 65 if (s0.r-r<=s1.r && s0.g-g<=s1.g && s0.b-b<=s1.b) { 66 res = getfct(s0.r-r,s0.g-g,s0.b-b) * dfs(s0.end(),s0.r-r,s0.g-g) % mod; 67 } 68 } else if (s0.end() > s1.end()) { 69 if (s1.r<=s0.r-r && s1.g<=s0.g-g && s1.b<=s0.b-b) { 70 res = getfct(s1.r,s1.g,s1.b) * dfs(s1.end(),r+s1.r,g+s1.g) % mod; 71 } 72 } 73 } 74 dp[t][r][g] = (int)res; 75 return res; 76 } 77 } 78 79 int WinterAndShopping::getNumber(vector <int> f, vector <int> r, vector <int> g, vector <int> b) { 80 pretreat(f,r,g,b); 81 memset(dp,-1,sizeof(dp)); 82 long long ans = dfs(0,0,0); 83 return (int)ans; 84 }