[关闭]
@Cyani 2020-04-30T08:53:40.000000Z 字数 1930 阅读 979

GP of Tokyo D. Xor Sum


问题需要求的是 “最大值最小”,可以想到二分答案 ,变成判定性问题。

XOR 运算的每一位是独立的,由此我们先独立地考虑每一位。假设第 位有 个数为 ,那么 变成限制所有 的奇偶性。

的第 位(如果 是奇数先特判),可以发现 一组合法的初始解。同时,所有的解可以通过不断操作 「 减二, 加四」来得到。

加下来的方向可能也只有按数位从高到低 DP 了。有了 的限制之后,我们让状态的第二维为「当前有多少个 卡到 的上界」,称其为 “自由位”。设 为:当前考虑第 位,有 卡到上界,最少需要多少进位(也即当前位操作数量)。可以做到关于 的多项式复杂度。

考虑缩小 的状态数量。一个重要的性质是,如果「当前 ,自由位的数量至少为 ,同时不需要进位」,那么 一定可行。这是因为 的初始解 ,一旦有 个数成为自由位,可以令后面的其他位都是 ,由这 个数字自由调整。

设之前退下来的位加上当前的初始解为 ,也即当前位需要的 的个数(可以继续往后退)。如果当前 ,那么只能继续往后退。接下来,如果 并且 ,直接返回 true(由前一段所述)。否则继续枚举 ,表示新的自由位个数。继续观察可以发现一个更重要的性质:当 的时候,如果 显然是更不优的(由于奇偶性的限制, 的转移是必要的),当 足够大的时候,我们最优化的目标只有 需要的进位最少

所以需要考虑的 的上界只有 ... 由此我们得到了一个 的做法。

  1. #include<bits/stdc++.h>
  2. #define rep(i,a,b) for(int i=(a);i<=(b);i++)
  3. #define per(i,a,b) for(int i=(a);i>=(b);i--)
  4. #define REP(i,n) for(int i=0;i<(n);i++)
  5. #define fi first
  6. #define se second
  7. #define pb push_back
  8. #define mp make_pair
  9. #define lc (o<<1)
  10. #define rc (o<<1|1)
  11. #define mid ((l+r)>>1)
  12. using namespace std;
  13. typedef pair<int,int> pii;
  14. typedef vector<int> vi;
  15. typedef long long ll;
  16. template<class T> void read(T &x){
  17. int f=0; x=0; char ch=getchar();
  18. for(;!isdigit(ch);ch=getchar()) f|=(ch=='-');
  19. for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
  20. }
  21. const ll inf=2e18;
  22. const int N=70;
  23. ll f[N],g[N];
  24. //j>=3且没有进位时,直接返回1
  25. //j较大时,显然最多j只会增加1
  26. int chk(ll n,ll s,ll x,ll v){
  27. s-=x;
  28. if(s<0||s%2) return 0;
  29. s/=2;
  30. int m=min(3ll,n);
  31. REP(i,N) f[i]=inf;
  32. f[0]=0;
  33. per(i,60,0){
  34. REP(j,N) g[j]=inf;
  35. rep(j,0,m){
  36. ll now=f[j]*4+(x>>i&1)+(s>>i&1)*2;
  37. if(!(v>>i&1)){
  38. ll e=(max(now-j,0ll)+1)/2;
  39. if(e*2<=now) g[j]=min(g[j],e);
  40. continue;
  41. }
  42. if(now<=n&&min(n-now+j,n)>=3) return 1;
  43. for(int k=j;k<=n&&(k<5||k-j<=1);k++){
  44. ll u=n-k+j;
  45. if(u>=now%2){
  46. ll e=now-min(now,(u-now%2)/2*2+now%2);
  47. g[k]=min(g[k],e/2);
  48. }
  49. }
  50. }
  51. m=min(m+1ll,n);
  52. swap(f,g);
  53. }
  54. rep(i,0,m) if(!f[i]) return 1;
  55. return 0;
  56. }
  57. void rmain(){
  58. ll n,s,x;
  59. cin>>n>>s>>x;
  60. ll l=0,r=s+1;
  61. while(l<r){
  62. ll m=(l+r)>>1;
  63. if(chk(n,s,x,m)) r=m;
  64. else l=m+1;
  65. }
  66. cout<<(l==s+1?-1:l)<<endl;
  67. }
  68. int main(){
  69. int T; read(T);
  70. while(T--) rmain();
  71. return 0;
  72. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注