[关闭]
@2368860385 2020-11-07T03:01:35.000000Z 字数 5978 阅读 195

后:day1

衢州
2018.8.4


预计:30+50+10
实际:30+50+10

考试总结:

T1

没头绪。

T2

写完50分dp,之后就不会了。临近结束半小时,发现转移具有单调性。然后也没有写出,也不会用这个单调性做什么。

T3

一眼感觉是搜索+meet in the middle,数据范围刚好是。想到一个很麻烦的搜索(调不出来的搜索),然后到最后也没有想到什么。

总结:

T3没有再想别的,
T2感觉有单调性,直到最后才打表试了试,应该早试试。
加强码力,分配好时间。


题解:

T1

__builtin_popcount(x) 计算x的二进制下1的个数。

考虑两个二进制数,它们异或后的结果是:x的1 + y的1 - 两个数的某一位上都有的1(即异或后会同时消失的1)。
101011
110101
答案就是 4 + 4 - 4。

那么会发现,消掉的1,一次会消一对,同时消去两个。所以两个数是不是好的 只与 两个数二进制下1的个数总和是不是奇数有关
那么就是要求x,y中一个数的二进制位下右奇数个,一个有偶数个。
那么统计答案就是统计奇数个1的个数 * 偶数个1的个数

查询区间有多少个偶数个1的数 与 有奇数个1的数 => 查询区间有多少个偶数个1的数。(奇数个1的数可以用区间长度做差)
查询区间[l,r]中有多少个偶数个1的数=>查询区间[1,r]-区间[1,l-1]。

所以问题转化为:查询[1,m]中有多少个数 的二进制下有偶数个1。
0 1 2 3 4 5
(01)(23)(45)
两两一组,其中相邻的两个数的1的个数一奇一偶。
m是奇数:(m+1)/2
m是偶数:m/2+[m是否有偶数个1]

线段树离散化 或者 动态加点线段树。

T2

50分:将所有的奇数 往 偶数的空隙中放,f[i][j]表示第i个奇数,往偶数的第j个空隙中放的,逆序对最少是多少。
发现转移具有单调性,

首先求出原来序列的逆序对,然后计算将奇数放入后的贡献。
考虑每个奇数放到哪里。
将x放到i后面的贡献是:



第二步:因为小于x的数一共有x/2个,而i后面的小于x的数,可以用x/2-i前面小于x的数算出。
(其实这些式子没什么用)

假设当前已经知道了x放到每个i后面的答案,然后x变成了x+2,那么会发现只有x+1这个偶数会对答案产生变化,如果x+2在这个数前面放,那么答案原来的答案+1,否则-1。
所以就是查询最小值,区间求改,所以线段树可以做。

做法:
首先求出1放到每个位置的答案(因为1比所有偶数小,所以放到i后面答案就是i,放到0号位置就是0)。
然后求出最小值就是1的答案。
对于3,那么找到2的位置是pos,那么3放到pos前面的所有位置,就会产生原来的基础上增加1个逆序对,0~pos-1 加1,放到pos后面的所有位置,在原来的基础上减一,pos~n减1(1放到这里会有(2,1)这个逆序对,而3放到这里没有,所以-1)。
以此类推。在线段树上完成这些操作即可。

标程:
直接对式子的后面那一部分,用线段树维护,同样分为插入到pos前面和后面的情况,前面不变,后面-2。

T3

15分:状压dp。
三重容斥。


第一题的代码:

离散化:将所有端点坐标离散化

  1. for (int i=1; i<=n; ++i) A[i] = read(), tmp[++m] = A[i];
  2. sort(tmp+1,tmp+m+1);
  3. int cnt = 1;
  4. for (int i=2; i<=m; ++i) tmp[++cnt] = tmp[i];
  5. int pos=lower_bound(tmp+1,tmp+1+m,A[i])-tmp;

然后在线段树时,即用tmp代替了原来的下标。

  1. void Insert(int rt,int l,int r,int L,int R)
  2. if (vis[rt]) return ;
  3. if (L <= l && r <= R) {
  4. sum[rt][0] = get(tmp[r]) - get(tmp[l]-1);
  5. sum[rt][1] = tmp[r] - tmp[l] + 1 - sum[rt][0];
  6. // ...
  7. //...
  8. void query() {
  9. int l=lower_bound(tmp+1,tmp+1+m,L[i])-tmp; //l,r离散化后tmp中的的坐标,L[i],R[i]第i个查询
  10. int r=lower_bound(tmp+1,tmp+1+m,R[i]+1)-tmp-1; //
  11. Insert(1,1,m,l,r); // m为所有端点的集合大小。
  12. }

动态加点的线段树

  1. void Insert(int &rt,LL l,LL r,LL L,LL R) {
  2. if (!rt) rt = ++CntNode;
  3. if (vis[rt]) return ;
  4. if (L <= l && r <= R) {
  5. sum[rt][0] = get(r) - get(l-1);
  6. sum[rt][1] = r - l + 1 - sum[rt][0];
  7. //...
  8. //...
  9. }
  10. void query() {
  11. int l = read(), r = read();
  12. Insert(Root,1,1LL<<32,l,r);
  13. }

标算(离散化):

  1. #include<stdio.h>
  2. #include<cstring>
  3. #include<cstdlib>
  4. #include<algorithm>
  5. #include<vector>
  6. #include<map>
  7. #include<set>
  8. #include<cmath>
  9. #include<iostream>
  10. #include<assert.h>
  11. #include<queue>
  12. #include<string>
  13. using namespace std;
  14. #define fi first
  15. #define se second
  16. #define pb push_back
  17. #define mp make_pair
  18. #define rep(i,j,k) for (int i=(int)(j);i<=(int)(k);i++)
  19. #define per(i,j,k) for (int i=(int)(j);i>=(int)(k);i--)
  20. typedef long long LL;
  21. const int N=210000;
  22. LL f[34][2][2];
  23. int ttmp[35];
  24. LL get0(LL r){
  25. if(r==0)return 1;
  26. //0..r
  27. memset(f,0,sizeof f);
  28. int m=0;
  29. while(r){
  30. ttmp[++m]=(r%2);
  31. r/=2;
  32. }
  33. reverse(ttmp+1,ttmp+1+m);
  34. f[0][1][0]=1;
  35. rep(i,0,m-1)rep(eq,0,1)rep(v,0,1){
  36. rep(c,0,1){
  37. if(eq&&(c>ttmp[i+1]))continue;
  38. f[i+1][eq&(c==ttmp[i+1])][v^c]+=f[i][eq][v];
  39. }
  40. }
  41. return f[m][0][0]+f[m][1][0];
  42. }
  43. int n;
  44. LL l[N],r[N];
  45. LL tmp[N];
  46. int m;
  47. //si:[tmp[i],tmp[i+1]-1]
  48. LL w[2];
  49. int mes[N<<2];
  50. void build(int me,int l,int r){
  51. mes[me]=r-l+1;
  52. if(l==r)return;
  53. int mid=(l+r)>>1;
  54. build(me<<1,l,mid);
  55. build(me<<1|1,mid+1,r);
  56. }
  57. void cov(int me,int l,int r,int x,int y){
  58. if(!mes[me])return;
  59. if(l==r){
  60. //printf("_%lld %lld\n",tmp[l],tmp[l+1]-1);
  61. LL cc=get0(tmp[l+1]-1)-get0(tmp[l]-1);
  62. w[0]+=cc;
  63. w[1]+=tmp[l+1]-tmp[l]-cc;
  64. mes[me]=0;
  65. return;
  66. }
  67. int mid=(l+r)>>1;
  68. if(x<=mid)cov(me<<1,l,mid,x,y);
  69. if(y>mid)cov(me<<1|1,mid+1,r,x,y);
  70. mes[me]=mes[me<<1]+mes[me<<1|1];
  71. }
  72. int main(){
  73. scanf("%d",&n);
  74. rep(i,1,n){
  75. scanf("%lld%lld",&l[i],&r[i]);
  76. tmp[++m]=r[i]+1;
  77. tmp[++m]=l[i];
  78. }
  79. sort(tmp+1,tmp+1+m);
  80. m=unique(tmp+1,tmp+1+m)-tmp-1;
  81. build(1,1,m);
  82. rep(i,1,n){
  83. int l1=lower_bound(tmp+1,tmp+1+m,l[i])-tmp;
  84. int r1=lower_bound(tmp+1,tmp+1+m,r[i]+1)-tmp-1;
  85. cov(1,1,m,l1,r1);
  86. unsigned long long ans=w[0]*w[1];
  87. printf("%llu\n",ans);
  88. }
  89. return 0;
  90. }

我的代码(动态加点):

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<cstring>
  4. #include<cmath>
  5. #include<iostream>
  6. #include<cctype>
  7. #include<set>
  8. #include<map>
  9. #include<queue>
  10. #include<vector>
  11. using namespace std;
  12. typedef long long LL;
  13. inline LL read() {
  14. LL x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
  15. for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
  16. }
  17. const int N = 800010;
  18. LL sum[N][2];
  19. int ls[N], rs[N], Root, CntNode;
  20. bool vis[N];
  21. LL get(LL x) {
  22. if (x & 1) return (x + 1) / 2 - 1; // 没有0,所以-1
  23. return x / 2 + !(__builtin_popcount(x) & 1) - 1;
  24. }
  25. void Insert(int &rt,LL l,LL r,LL L,LL R) {
  26. if (!rt) rt = ++CntNode;
  27. if (vis[rt]) return ;
  28. if (L <= l && r <= R) {
  29. sum[rt][0] = get(r) - get(l-1);
  30. sum[rt][1] = r - l + 1 - sum[rt][0];
  31. vis[rt] = true;
  32. return ;
  33. }
  34. LL mid = (l + r) >> 1;
  35. if (L <= mid) Insert(ls[rt], l, mid, L, R);
  36. if (R > mid) Insert(rs[rt], mid+1, r, L, R);
  37. sum[rt][1] = sum[ls[rt]][1] + sum[rs[rt]][1];
  38. sum[rt][0] = sum[ls[rt]][0] + sum[rs[rt]][0];
  39. }
  40. int main() {
  41. int n; cin >> n;
  42. for (int i=1; i<=n; ++i) {
  43. LL l = read(), r = read();
  44. Insert(Root, 1, 1LL<<32, l, r);
  45. printf("%lld\n",sum[Root][1] * sum[Root][0]);
  46. }
  47. return 0;
  48. }

T2代码

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<cstring>
  4. #include<iostream>
  5. #include<cctype>
  6. using namespace std;
  7. typedef long long LL;
  8. inline int read() {
  9. int x = 0, f = 1; char ch = getchar(); for (; !isdigit(ch); ch=getchar()) if (ch=='-') f = -1;
  10. for (; isdigit(ch); ch=getchar()) x = x * 10 + ch - '0'; return x * f;
  11. }
  12. const int N = 200100;
  13. int pos[N], a[N];
  14. struct BIT{
  15. int n, sum[N];
  16. void update(int p,int v) {
  17. for (; p<=n; p+=(p&(-p))) sum[p] += v;
  18. }
  19. int query(int p) {
  20. int ans = 0;
  21. for (; p; p-=(p&(-p))) ans += sum[p];
  22. return ans;
  23. }
  24. }bit;
  25. #define Root 1, 0, tn
  26. #define lson rt << 1, l, mid
  27. #define rson rt << 1 | 1, mid + 1, r
  28. struct Seg{
  29. int tag[N << 1], Mn[N << 1];
  30. void pushup(int rt) {
  31. Mn[rt] = min(Mn[rt << 1], Mn[rt << 1 | 1]);
  32. }
  33. void pushdown(int rt) {
  34. if (tag[rt]) {
  35. tag[rt << 1] += tag[rt];
  36. tag[rt << 1 | 1] += tag[rt];
  37. Mn[rt << 1] += tag[rt];
  38. Mn[rt << 1 | 1] += tag[rt];
  39. tag[rt] = 0;
  40. }
  41. }
  42. void build(int rt,int l,int r) {
  43. if (l == r) {
  44. Mn[rt] = l;
  45. return ;
  46. }
  47. int mid = (l + r) >> 1;
  48. build(lson);
  49. build(rson);
  50. pushup(rt);
  51. }
  52. void update(int rt,int l,int r,int L,int R,int x) {
  53. if (L <= l && r <= R) {
  54. Mn[rt] += x;
  55. tag[rt] += x;
  56. return ;
  57. }
  58. pushdown(rt);
  59. int mid = (l + r) >> 1;
  60. if (L <= mid) update(lson, L, R, x);
  61. if (R > mid) update(rson, L, R, x);
  62. pushup(rt);
  63. }
  64. }T;
  65. int main() {
  66. int n = read(), tn = n / 2;
  67. for (int i=1; i<=tn; ++i)
  68. a[i] = read(), pos[a[i]] = i;
  69. bit.n = n;
  70. LL Ans = 0;
  71. for (int i=tn; i>=1; --i) {
  72. Ans += bit.query(a[i] - 1);
  73. bit.update(a[i], 1);
  74. }
  75. T.build(Root);
  76. for (int i=1; i<=n; i+=2) {
  77. Ans += T.Mn[1];
  78. T.update(Root, 0, pos[i + 1] - 1, 1);
  79. T.update(Root, pos[i + 1], tn, -1);
  80. }
  81. cout << Ans;
  82. return 0;
  83. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注