E - Everyone wants Khaleesi
考虑A先走一步到达点x,首先x要是必胜点,x是必胜点的条件是:如果x不是n的话,那么x出度的点必须有两个必胜点,否则B一定可以割掉通往必胜点的路径。n点是必胜点,从n点往前推,会发现所有点都是必败点,因为是dag。所以除非A可以一步到达点n,否则A必败。
F - Flipping Rectangles
考虑将r1移到和r2有面积交的地方需要多少步,和k比较大小,接下来就是枚举上下方向移动一步,左右方向移动一步即可。
G - Gift Pack
数位$ dp $。这个题比较容易想贪心,譬如说我当时在比赛过程中,想贪心的从高位开始取,但是很容易发现,如果枚举该位的$8$种情况,并非只会产生$0$或者$1$,也可能产生$2$,也就是说,会产生进位,这样贪心就不对了。正确的做法是,我们可以数位$dp$,用$dp[i][al][ar][b][c]$表示从最高位到第i位的贴边界的情况为$(al,ar,b,c)$时的最大答案,其中$(al,ar,b,c)$分别指第一个数是否贴下界,第一个数是否贴上界,第二个数是否贴上界以及第三个数是否贴上界,转移的话,只要枚举该位的$8$种情况,判断下是否越界,将所有情况取最大即可。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 typedef long long ll; 5 typedef std::pair<ll,ll> P; 6 ll dp[66][2][2][2][2]; 7 ll L,R,A,B; 8 ll dfs(int pos,bool al,bool ar,bool b,bool c) { 9 if(pos<0) return 0; 10 if(dp[pos][al][ar][b][c]!=-1) return dp[pos][al][ar][b][c]; 11 int aL=0,aR=1,upb=1,upc=1; 12 if(al) aL=L>>pos&1; 13 if(ar) aR=R>>pos&1; 14 if(b) upb=A>>pos&1; 15 if(c) upc=B>>pos&1; 16 ll &ans=dp[pos][al][ar][b][c]; 17 for(int i=0;i<8;i++) { 18 int na,nb,nc; 19 na=i&1; 20 nb=i>>1&1; 21 nc=i>>2&1; 22 if(na<aL||na>aR) continue; 23 if(nb>upb) continue; 24 if(nc>upc) continue; 25 ll tmp=(na^nb)+(na^nc)+(nb&nc); 26 tmp<<=pos; 27 ans=std::max(ans,tmp+dfs(pos-1,al&&na==aL,ar&&na==aR,b&&nb==upb,c&&nc==upc)); 28 } 29 return ans; 30 } 31 int main() { 32 int n; 33 //printf("%lld\n",1LL<<61); 34 scanf("%d",&n); 35 while(n--) { 36 scanf("%lld%lld%lld%lld",&L,&R,&A,&B); 37 memset(dp,-1,sizeof(dp)); 38 printf("%lld\n",dfs(61,1,1,1,1)); 39 } 40 return 0; 41 }