[SRM] 09 撕书狂魔CZL
A. 撕书Ⅰ
序列型DP。DP[i]表示当前编号结点的撕书页数。
那么我们有 DP[ i ] = DP[ i - y - 1 ] + y
其中y为编号i书页对应范围内的书页。
那么,具体实现的话,需要求出每个i对应的y,这里用前缀和。
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #define maxn 1000005 5 #define lowbit(x) (-x&x) 6 using namespace std; 7 8 int n,high = 0; 9 10 struct node{ 11 int pos,ai; 12 }list[maxn]; 13 14 int Tree[maxn],DP[maxn],minn; 15 int sum(int p){ 16 int ans = 0; 17 while(p){ 18 // cout << '^'; 19 // cout << p; 20 ans += Tree[p]; 21 p -= lowbit(p); 22 } 23 return ans; 24 } 25 void add(int p){ 26 while(p <= high){ 27 // cout << 'G'; 28 Tree[p]++; 29 p += lowbit(p); 30 // cout << p; 31 } 32 } 33 34 bool cmp(const node &a,const node &b){ 35 return a.pos < b.pos; 36 } 37 38 int main(){ 39 scanf("%d",&n); 40 41 for(int i = 1;i <= n;i++){ 42 scanf("%d%d",&list[i].pos,&list[i].ai); 43 list[i].pos++; 44 high = max(high,list[i].pos); 45 } 46 47 sort(list+1,list+1+n,cmp); 48 49 // printf("#%d#\n",high); 50 51 for(int i = 1;i <= n;i++){ 52 53 // cout << 'A'; 54 add(list[i].pos); 55 } 56 57 for(int i = 1;i <= n;i++){ 58 int a = list[i].pos-1; 59 int b = list[i].pos-list[i].ai-1; 60 if(a < 0) a = 0; 61 if(b < 0) b = 0; 62 int y = sum(a)-sum(b); 63 if(i-y-1 < 0) continue; 64 DP[i] = DP[i-y-1] + y; 65 } 66 67 minn = DP[n]; 68 69 for(int i = 1;i <= n;i++){ 70 minn = min(minn,DP[i]+n-i); 71 } 72 73 printf("%d",minn); 74 75 // cout << endl; 76 // for(int i = 0;i <= n;i++) printf("%d ",DP[i]); 77 78 // cout << endl; 79 // for(int i = 0;i <= 10;i++) printf("%d ",sum(i)); 80 81 return 0; 82 }
B. 撕书 Ⅱ
这道题略坑。
x表示a+b,y表示a^b,那么我们定义一个z = (x-y)>> 1。
这个z表示的就是有a+b进位的位(准确来说是a x b == 1)
为什么呢?
因为某些原因,异或等于没有进位的加,那么和就拥有异或结果所没有的进位的信息。
和 - 异或 就可以去除其他冗余,得到进位的信息啦!
然而需要右移一位才能精确表示。
那么显然不合法的情况就包括:
1. x < y :显然根据前文我们有 x ≥ y
2. ( x - y ) & 1 != 0: ( x - y )>>1 表示有进位的二进制位,如果命题成立,-1位有进位是什么鬼??
还有特殊情况:
如果 x == y ,ans 需要减少2
因为此时 a 和 b 可以有一个为0,所以需要排除这种情况。
求解策略:
如果 y 的一个二进制位为 1 ,显然 a 和 b 其中一个为 0 且另一个为 1 ,那么有两种情况,ans *= 2
如果 y 的一个二进制位为 0 ,显然 a 和 b 的对应二进制位是相同的,ans *= 1
以此检验 x 和 y 的每一位,ans也就出来了。
1 #include<cstdio> 2 #include<iostream> 3 #define LL long long 4 using namespace std; 5 6 LL x,y,z,ans = 1; 7 8 int main(){ 9 scanf("%lld%lld",&x,&y); 10 11 z = x-y; 12 13 if(z&1L || x < y){ 14 printf("0"); 15 return 0; 16 } 17 18 z >>= 1; 19 20 // for(LL i = 1;i <= x;i<<=1){ 21 // printf("%d",(z&i)?1:0);. 22 // } 23 24 // cout << endl; 25 26 for(LL a = 0;(1L<<a) <= x;a++){ 27 // printf("%d",((1L<<a)&x)^((1L<<a)&z)?1:0); 28 if(y&(1L<<a)){ 29 if(z&(1L<<a)){ 30 // printf("*%lld*\n",a); 31 // if((x&a) == (z&a)) cout << " dfdfdfd"; 32 // cout << "#" << (x&a); 33 // cout << "#" << (z&a); 34 printf("0"); 35 return 0; 36 } 37 38 ans *= 2; 39 } 40 // if(y&a) ans *= 2; 41 } 42 43 if(x == y) ans -= 2; 44 45 46 printf("%lld",ans); 47 48 return 0; 49 }
转载请注明出处 -- 如有意见欢迎评论