第二次参加USACO 本来打算2016-2017全勤的 January的好像忘记打了 听群里有人讨论才想起来
铂金组三题很有意思,都是两个排列的交叉对问题 我最后得分889/1000(真的菜)

T1.Why Did the Cow Cross the Road
题目大意:给出两个N个排列(N<=100,000),允许把其中一个排列循环移动任意位,a[i]表示i在第一个排列中的位置,b[i]表示第二个,定义交叉对(i,j)满足a[i]<a[j]且b[i]>b[j],求最少交叉对。
思路:数字大小没有影响,于是令第一个排列中第一个出现的编号为1,第二个出现的编号为2,于是变成最小化第二个排列的逆序对,一开始的逆序对可以O(nlogn)求出,然后考虑把当前第一个数移到最后,若这个数编号为x,明显多了n-x个逆序对,少了x-1个逆序对,就可以O(n)求出所有循环移动第二个排列的情况,然后我开心的交了,开心的WA了,后来才知道,自己忘记考虑移第一个的情况了(其实只要反过来再做一遍)。
得分:8/10(幸好数据大多是移第二个的?)

  1. #include<cstdio>
  2. #include<iostream>
  3. using namespace std;
  4. char B[<<],*S=B,C;int X;
  5. inline int read()
  6. {
  7. while((C=*S++)<''||C>'');
  8. for(X=C-'';(C=*S++)>=''&&C<='';)X=(X<<)+(X<<)+C-'';
  9. return X;
  10. }
  11. #define MN 100000
  12. #define N 131072
  13. int f[MN+],a[MN+],t[N*];
  14. void inc(int k){for(k+=N;k;k>>=)++t[k];}
  15. int query(int l,int r)
  16. {
  17. int res=;
  18. for(l+=N-,r+=N+;l^r^;l>>=,r>>=)
  19. {
  20. if(~l&)res+=t[l+];
  21. if( r&)res+=t[r-];
  22. }
  23. return res;
  24. }
  25. int main()
  26. {
  27. freopen("mincross.in","r",stdin);
  28. freopen("mincross.out","w",stdout);
  29. fread(B,,<<,stdin);
  30. int n=read(),i;long long ans,cnt=;
  31. for(i=;i<=n;++i)f[read()]=i;
  32. for(i=;i<=n;++i)cnt+=query(a[i]=f[read()],n),inc(a[i]);
  33. for(ans=cnt,i=;i<n;++i)if((cnt+=n-(a[i]<<)+)<ans)ans=cnt;
  34. cout<<ans;
  35. }

AC代码

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<iostream>
  4. using namespace std;
  5. char B[<<],*S=B,C;int X;
  6. inline int read()
  7. {
  8. while((C=*S++)<''||C>'');
  9. for(X=C-'';(C=*S++)>=''&&C<='';)X=(X<<)+(X<<)+C-'';
  10. return X;
  11. }
  12. #define MN 100000
  13. #define N 131072
  14. int c[MN+],d[MN+],f[MN+],a[MN+],t[N*];
  15. void inc(int k){for(k+=N;k;k>>=)++t[k];}
  16. int query(int l,int r)
  17. {
  18. int res=;
  19. for(l+=N-,r+=N+;l^r^;l>>=,r>>=)
  20. {
  21. if(~l&)res+=t[l+];
  22. if( r&)res+=t[r-];
  23. }
  24. return res;
  25. }
  26. int main()
  27. {
  28. freopen("mincross.in","r",stdin);
  29. freopen("mincross.out","w",stdout);
  30. fread(B,,<<,stdin);
  31. int n=read(),i;long long ans,cnt=;
  32. for(i=;i<=n;++i)f[c[i]=read()]=i;
  33. for(i=;i<=n;++i)cnt+=query(a[i]=f[d[i]=read()],n),inc(a[i]);
  34. for(ans=cnt,i=;i<n;++i)if((cnt+=n-(a[i]<<)+)<ans)ans=cnt;
  35. for(i=;i<=n;++i)f[d[i]]=i;
  36. memset(t,cnt=,sizeof(t));
  37. for(i=;i<=n;++i)cnt+=query(a[i]=f[c[i]],n),inc(a[i]);
  38. for(ans=min(ans,cnt),i=;i<n;++i)if((cnt+=n-(a[i]<<)+)<ans)ans=cnt;
  39. cout<<ans;
  40. }

T2.Why Did the Cow Cross the Road II
题目大意:两个排列排成两排(长度<=100,000),两排间相差不超过4的可以连边,边不能有交叉,问最多连几条。
思路:金组也有这道,不过N只有1000,考虑DP,f[i][j]表示第一个排列用到第i个 ,第二个排列用到第j个,最多连几条边,f[i][j]=max(f[i-1][j],f[i][j-1]),若a[i]和b[j]相差不超过4,f[i][j]=max(f[i][j],f[i-1][j-1]+1),就能O(n^2)完成。由于对于每个a[i],相差不超过4的b[j]的最多9个,我们把状态的j改成用了j,每个f[i]相对f[i-1]只变了9个,然后拿线段树维护一下就可以O(9nlogn)来DP了。
得分:10/10

  1. #include<cstdio>
  2. #include<algorithm>
  3. using namespace std;
  4. char B[<<],*S=B,C;int X;
  5. inline int read()
  6. {
  7. while((C=*S++)<''||C>'');
  8. for(X=C-'';(C=*S++)>=''&&C<='';)X=(X<<)+(X<<)+C-'';
  9. return X;
  10. }
  11. #define MN 100000
  12. #define N 131072
  13. int a[MN+],b[MN+],t[N*],g[];
  14. void renew(int k,int x){for(k+=N;k;k>>=)t[k]=max(t[k],x);}
  15. int query(int l,int r)
  16. {
  17. int res=;
  18. for(l+=N-,r+=N+;l^r^;l>>=,r>>=)
  19. {
  20. if(~l&)res=max(res,t[l+]);
  21. if( r&)res=max(res,t[r-]);
  22. }
  23. return res;
  24. }
  25. int main()
  26. {
  27. freopen("nocross.in","r",stdin);
  28. freopen("nocross.out","w",stdout);
  29. fread(B,,<<,stdin);
  30. int n=read(),i,j;
  31. for(i=;i<=n;++i)a[i]=read();
  32. for(i=;i<=n;++i)b[read()]=i;
  33. for(i=;i<=n;++i)
  34. {
  35. for(j=-;j<=;++j)if(a[i]+j>&&a[i]+j<=n)g[j+]=query(,b[a[i]+j]-)+;
  36. for(j=-;j<=;++j)if(a[i]+j>&&a[i]+j<=n)renew(b[a[i]+j],g[j+]);
  37. }
  38. printf("%d",query(,n));
  39. }

T3.Why Did the Cow Cross the Road III
题目大意:两个排列(长度<=100,000),相等的连边,相差超过K的称为不友好,求不友好交叉对。
思路:我比较菜,只会暴力,考虑对每对相等的计算答案,每对a[i]=b[j],把a[i]左边设成1,右边设成0,b[j]同样,与这条边有交叉的边必然被编成一个1,1个0,也就是异或为1,考虑统计答案,做法1:把每个值现在的两个编码的异或值用树状数组维护,把每条边的当成一个二维询问,考虑莫队,插入和删除一个值都相当于令这个值编码的异或值异或上1,复杂度O(n^1.5logn);做法2:用可持久化bitset搞出两个排列所有前缀后缀的bitset,bitset里存每个值的编码,每条边都拿出bitset异或一下,复杂度O(n^2/32)。我比较懒,写了莫队,一开始T了六七个,调了下块大小,最后在K=3n^0.5左右只T两个点,玄妙无比。另外用sum(n)-sum(i+k)统计貌似比sum(i-k-1)多过了一个点,原理不明。
得分:13/15

  1. #include<cstdio>
  2. #include<iostream>
  3. #include<algorithm>
  4. using namespace std;
  5. char B[<<],*S=B,C;int X;
  6. inline int read()
  7. {
  8. while((C=*S++)<''||C>'');
  9. for(X=C-'';(C=*S++)>=''&&C<='';)X=(X<<)+(X<<)+C-'';
  10. return X;
  11. }
  12. #define MN 100000
  13. #define K 1050
  14. #define lb(x) (x&-x)
  15. int a[MN+],b[MN+],f[MN+],s[MN+];
  16. struct query{int a,b,x;}q[MN+];
  17. bool cmp(query a,query b){return a.a/K==b.a/K?a.b<b.b:a.a<b.a;}
  18. int sum(int x){int r=;for(;x;x-=lb(x))r+=s[x];return r;}
  19. void rev(int x){int r=(f[x]^)-f[x];f[x]^=;for(;x<=MN;x+=lb(x))s[x]+=r;}
  20. int main()
  21. {
  22. freopen("friendcross.in","r",stdin);
  23. freopen("friendcross.out","w",stdout);
  24. fread(B,,<<,stdin);
  25. int n,k,i,pa=,pb=;long long ans=;
  26. n=read();k=read();
  27. for(i=;i<=n;++i)a[i]=read(),q[a[i]].a=i,q[a[i]].x=a[i]+k;
  28. for(i=;i<=n;++i)b[i]=read(),q[b[i]].b=i;
  29. sort(q+,q+n+,cmp);
  30. for(i=;i<=n;++i)
  31. {
  32. if(q[i].x>=n)continue;
  33. while(pa<q[i].a)rev(a[++pa]);
  34. while(pa>q[i].a)rev(a[pa--]);
  35. while(pb<q[i].b)rev(b[++pb]);
  36. while(pb>q[i].b)rev(b[pb--]);
  37. ans+=sum(n)-sum(q[i].x);
  38. }
  39. cout<<ans;
  40. }

正解:把每个数字在两个排列中的位置抽象到二维平面上(例如1在第一个排列中排第2个,在第二个排列中排第3,则用(2,3)表示),那么若两个数字交叉,则其中一个数字在二维平面上必然在另一个点的左上方(一维小,另一维大),要统计不友好交叉对,对每个点i统计1~i-k-1,i+k+1~n中有多少个点在他左上就好了,考虑把两个分开处理,可以依次插入点i,询问点i+k+1,插入点i+1,询问点i+k+2……另一个反过来再做一遍就能算出答案。这个问题可以用cdq分治或者二维线段树解决,复杂度O(nlogn^2)。

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<iostream>
  4. using namespace std;
  5. #define ll long long
  6. char B[<<],*S=B,C;int X;
  7. inline int read()
  8. {
  9. while((C=*S++)<''||C>'');
  10. for(X=C-'';(C=*S++)>=''&&C<='';)X=(X<<)+(X<<)+C-'';
  11. return X;
  12. }
  13. #define MN 100000
  14. int a[MN+],b[MN+],t[MN*+],x[MN*+],y[MN*+],s[MN+];ll ans;
  15. struct query{int x,y,t;}q[MN*+];
  16. bool cmp(query a,query b){return a.x<b.x;}
  17. void inc(int x,int z){for(;x<=MN;x+=x&-x)s[x]+=z;}
  18. int sum(int x){int r=;for(;x;x-=x&-x)r+=s[x];return r;}
  19. void solve(int l,int r)
  20. {
  21. if(l>=r)return;
  22. int i,mid=l+r>>,qn;
  23. for(i=l,qn=;i<=mid;++i)if(t[i])q[++qn]=(query){x[i],y[i],t[i]};
  24. for(i=mid;++i<=r;)if(!t[i])q[++qn]=(query){x[i],y[i],t[i]};
  25. sort(q+,q+qn+,cmp);
  26. for(i=;i<=qn;++i)
  27. if(q[i].t)inc(q[i].y,);
  28. else ans+=sum(MN)-sum(q[i].y);
  29. for(i=;i<=qn;++i)if(q[i].t)inc(q[i].y,-);
  30. solve(l,mid);solve(mid+,r);
  31. }
  32. int main()
  33. {
  34. freopen("friendcross.in","r",stdin);
  35. freopen("friendcross.out","w",stdout);
  36. fread(B,,<<,stdin);
  37. int n,k,i,cnt;
  38. n=read();k=read();
  39. for(i=;i<=n;++i)a[read()]=i;
  40. for(i=;i<=n;++i)b[read()]=i;
  41. for(cnt=,i=;i+k+<=n;++i)
  42. {
  43. x[++cnt]=a[i];y[cnt]=b[i];t[cnt]=;
  44. x[++cnt]=a[i+k+];y[cnt]=b[i+k+];t[cnt]=;
  45. }
  46. solve(,cnt);
  47. for(cnt=,i=n;i-k-;--i)
  48. {
  49. x[++cnt]=a[i];y[cnt]=b[i];t[cnt]=;
  50. x[++cnt]=a[i-k-];y[cnt]=b[i-k-];t[cnt]=;
  51. }
  52. solve(,cnt);
  53. cout<<ans;
  54. fclose(stdin);fclose(stdout);return ;
  55. }

USACO 2017 February Platinum的更多相关文章

  1. USACO 2017 February Gold

    那天打cf前无聊练手 T1.Why Did the Cow Cross the Road 题目大意:N*N的矩阵,从左上角走到右下角,走一步消耗T,每走3步消耗当前所在位置上的权值,求最小消耗 思路: ...

  2. USACO 2017 January Platinum

    因为之前忘做了,赶紧补上. T1.Promotion Counting 题目大意:给定一个以1为根的N个节点的树(N<=100,000),每个节点有一个权值,对于每个节点求出权值比它大的子孙的个 ...

  3. USACO 2017 FEB Platinum mincross 可持久化线段树

    题意 上下有两个位置分别对应的序列A.B,长度为n,两序列为n的一个排列.当Ai == Bj时,上下会连一条边.你可以选择序列A或者序列B进行旋转任意K步,如 3 4 1 5 2 旋转两步为 5 2 ...

  4. USACO 2017 FEB Platinum nocross DP

    题目大意 上下有两个长度为n.位置对应的序列A.B,其中数的范围均为1~n.若abs(A[i]-B[j]) <= 4,则A[i]与B[j]间可以连一条边.现要求在边与边不相交的情况下的最大的连边 ...

  5. Usaco 2019 Jan Platinum

    Usaco 2019 Jan Platinum 要不是昨天老师给我们考了这套题,我都不知道usaco还有铂金这么一级. 插播一则新闻:杨神坚持认为铂金比黄金简单,原因竟是:铜 汞 银 铂 金(金属活动 ...

  6. POJ1944 Fiber Communications (USACO 2002 February)

    Fiber Communications 总时间限制:  1000ms 内存限制:  65536kB 描述 Farmer John wants to connect his N (1 <= N ...

  7. [USACO 2017 Dec Gold] Tutorial

    Link: USACO 2017 Dec Gold 传送门 A: 为了保证复杂度明显是从终结点往回退 结果一开始全在想优化建边$dfs$……其实可以不用建边直接$multiset$找可行边跑$bfs$ ...

  8. NC24083 [USACO 2017 Dec P]Greedy Gift Takers

    NC24083 [USACO 2017 Dec P]Greedy Gift Takers 题目 题目描述 Farmer John's nemesis, Farmer Nhoj, has N cows ...

  9. USACO 2016 February Contest, Gold解题报告

    1.Circular Barn   http://www.usaco.org/index.php?page=viewproblem2&cpid=621 贪心 #include <cstd ...

随机推荐

  1. Beta敏捷冲刺每日报告——Day3

    1.情况简述 Beta阶段Scrum Meeting 敏捷开发起止时间 2017.11.4 00:00 -- 2017.11.5 00:00 讨论时间地点 2017.11.4 晚9:30,电话会议会议 ...

  2. LeetCode---Container With Most Water(11)

    Description: Given n non-negative integers a1, a2, ..., an, where each represents a point at coordin ...

  3. Codeforces 193 D. Two Segments

    http://codeforces.com/contest/193/problem/D 题意: 给一个1~n的排列,在这个排列中选出两段区间,求使选出的元素排序后构成公差为1的等差数列的方案数. 换个 ...

  4. 解决yii2中 Class yii/web/JsonParser does not exist, ReflectionException问题

    最近在调试RESTful API示例时,出现以下错误: { "name": "Exception", "message": "Cl ...

  5. GZip 压缩及解压缩

    /// <summary> /// GZipHelper /// </summary> public class GZipHelper { /// <summary> ...

  6. Linux系统把/home重新挂载到其他硬盘或分区

    一开始没有做好规划,导致/home空间不足,再加上分区表不是GPT,导致无法扩展超过2T,因此需要重新划分一块更大的硬盘给/home. 1.把新挂载的4T硬盘进行分区和格式化 2.创建目录 sudo ...

  7. Netty事件监听和处理(下)

    上一篇 介绍了事件监听.责任链模型.socket接口和IO模型.线程模型等基本概念,以及Netty的整体结构,这篇就来说下Netty三大核心模块之一:事件监听和处理. 前面提到,Netty是一个NIO ...

  8. hadoop原理

    MapReduce工作原理图文详解 前言:   前段时间我们云计算团队一起学习了hadoop相关的知识,大家都积极地做了.学了很多东西,收获颇丰.可是开学后,大家都忙各自的事情,云计算方面的动静都不太 ...

  9. 高级控件 popwindow 与gridview的组合应用

    Gridview 的布局设置 <GridView android:layout_width="wrap_content" android:layout_height=&quo ...

  10. Python系列之 - 面向对象(1)

    python是一门面向对象的编程语言,python中的一切均是对象. 有对象就提到类,对象和类就像是儿子和老子的关系,是不可分的一对. 什么是类     类就是具有一些共同特性的事物的统称.好比人类, ...