SDU暑期集训排位(1)题解

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 }
View Code

猜你喜欢

转载自www.cnblogs.com/Onlymyheart/p/11233547.html