经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C++ » 查看文章
长乐国庆集训Day3
来源:cnblogs  作者:Ra煞  时间:2019/10/8 9:32:46  对本文有异议

T1 动态逆序对

题目

【题目描述】

给出一个长度为n的排列a(1~n这n个数在数列中各出现1次)。每次交换两个数,求逆序对数%2的结果。

逆序对:对于两个数a[i],a[j](i<j),若a[i]>a[j],则(a[i],a[j])为1个逆序对。

【输入格式】

第一行一个正整数n。

接下来一行n个数,表示给出的排列a。

接下来一行一个正整数q。

接下来q行,每行两个正整数i,j,表示交换a[i]和a[j]。

【输出格式】

输出共q行,表示每次交换后的逆序对数%2的结果。

【输入样例】

  1. 4
  2. 1 2 3 4
  3. 2
  4. 1 2
  5. 1 2

【输出样例】

  1. 1
  2. 0

【数据规模】

对于60%的数据:n,q≤100;

对于80%的数据:n,q≤1000;

对于100%的数据:n,q≤100000。

解析

先求出初始序列的逆序对总数对2取余的结果。

每次交换a[i]与a[j](i<j),对于a[k]的影响如下:

  • 若k<i,a[k]依旧在a[i]与a[j]前面,所以a[k]与a[i]、a[j]产生的逆序对数不变;
  • 若k>j,同上,逆序对数不变;
  • 若i<k<j,如果a[i]<a[k],则逆序对数+1,否则-1,;如果a[j]>a[k],则逆序对数+1,否则-1,

而我们只需求出逆序对数对2取余的结果,可以发现,逆序对个数的奇偶性与k无关。

事实上,只需在每次交换位置时,令逆序对总数对2取余的结果^1即可(i=j时则不变)。

Code

  1. #include <algorithm>
  2. #include <iostream>
  3. #include <cstring>
  4. #include <string>
  5. #include <cstdio>
  6. #include <cmath>
  7. using namespace std;
  8. inline int read()
  9. {
  10. int num=0,w=1;
  11. char ch=getchar();
  12. while(ch<'0'||ch>'9')
  13. {
  14. if(ch=='-') w=-1;
  15. ch=getchar();
  16. }
  17. while(ch>='0'&&ch<='9')
  18. {
  19. num=(num<<1)+(num<<3)+ch-'0';
  20. ch=getchar();
  21. }
  22. return num*w;
  23. }
  24. int n,q,a[100100],f[100100],temp;
  25. void add(int x,int y)
  26. {
  27. for(;x<=n;x+=(x&-x)) f[x]+=y;
  28. }
  29. int ask(int x)
  30. {
  31. int ans=0;
  32. for(;x;x-=(x&-x)) ans+=f[x];
  33. return ans;
  34. }
  35. int main()
  36. {
  37. //freopen("lyk.in","r",stdin);
  38. //freopen("lyk.out","w",stdout);
  39. n=read();
  40. for(int i=1;i<=n;i++) a[i]=read();
  41. q=read();
  42. for(int i=n;i>=1;i--)
  43. {
  44. temp+=ask(a[i]-1);
  45. add(a[i],1);
  46. }
  47. temp&=1;
  48. for(int i=1;i<=q;i++)
  49. {
  50. int x=read(),y=read();
  51. if(x!=y) temp^=1;
  52. cout<<temp<<endl;
  53. }
  54. return 0;
  55. }
View Code

 

 

 

 

 

T2 树的统计

题目

【题目描述】

给出一棵n个点的满二叉树,根节点为1,第i个点的左右子节点分别为第2i,2i+1个点,第i个点的权值为a[i]。

有m个询问。对于每个询问给出x,d,求到点x的距离为d的所有点的点权和。如果不存在符合条件的点,输出0。

两点距离即两点间最短路径的边数。

保证最终答案在int范围内。

【输入格式】

第一行两个正整数n,m。

接下来n行每行一个正整数,第i行的数表示a[i]。

接下来m行每行两个整数x,d,表示一个询问。

【输出格式】

对于每个询问输出一行表示答案。

【输入样例】

  1. 7 3
  2. 13
  3. 7
  4. 2
  5. 9
  6. 5
  7. 6
  8. 8
  9. 1 3
  10. 4 2
  11. 3 1

【输出样例】

  1. 0
  2. 18
  3. 27

【数据规模】

对于80%的数据,n≤1023,m≤1000。

对于100%的数据,n≤131071,m≤100000,n=2t-1,1≤t≤17,a[i]≤30000。

解析

对于每个询问,用dfs搜索与点x距离为d的点,进行统计即可。

注意每个点之间的关系,访问父亲是x<<1,左儿子是x>>1,右儿子是x>>1+1,要特判一下左右儿子编号不能大于n,否则会RE。

Code

  1. #include <algorithm>
  2. #include <iostream>
  3. #include <cstring>
  4. #include <string>
  5. #include <cstdio>
  6. #include <cmath>
  7. #include <queue>
  8. using namespace std;
  9. inline int read()
  10. {
  11. int num=0,w=1;
  12. char ch=getchar();
  13. while(ch<'0'||ch>'9')
  14. {
  15. if(ch=='-') w=-1;
  16. ch=getchar();
  17. }
  18. while(ch>='0'&&ch<='9')
  19. {
  20. num=(num<<1)+(num<<3)+ch-'0';
  21. ch=getchar();
  22. }
  23. return num*w;
  24. }
  25. const int N=131073;
  26. int n,m,a[N],dd,ans;
  27. void dfs(int x,int d,int from)
  28. {
  29. if(d>dd) return ;
  30. if(d==dd)
  31. {
  32. ans+=a[x];
  33. return ;
  34. }
  35. int y=x>>1;
  36. if(y>=1&&y!=from) dfs(y,d+1,x);
  37. y=x<<1;
  38. if(y<=n&&y!=from) dfs(y,d+1,x);
  39. if(y+1<=n&&y+1!=from) dfs(y+1,d+1,x);
  40. }
  41. int main()
  42. {
  43. //freopen("dream.in","r",stdin);
  44. //freopen("dream.out","w",stdout);
  45. n=read(),m=read();
  46. a[1]=read();
  47. for(int i=2;i<=n;i++) a[i]=read();
  48. for(int i=1;i<=m;i++)
  49. {
  50. int x=read();
  51. dd=read(),ans=0;
  52. dfs(x,0,0);
  53. cout<<ans<<endl;
  54. }
  55. return 0;
  56. }
View Code

 

 

 

 

 

T3 宣传栏

题目

【题目描述】

有一个大型的矩形宣传栏,高和宽分别为h和m。宣传栏是用来张贴告示的地方,最初,宣传栏是空的,但此后告示将一张一张的被放上去。

有n张告示,每张告示的高都是一个单位长度,第i张贴上的告示宽度为w[i]。

每次张贴时,总是将告示贴在可以张贴且最高的地方,如果有多个可行的地方,则选择最左边张贴。

给定宣传栏的高和宽,你的任务是找出每个告示张贴在第几行。

【输入格式】

第一行为三个整数,h,m和n(1≤m≤109;1≤h≤n≤200000),表示宣传栏的尺寸和张贴的告示个数。

接下来n行表示w[i](1≤w[i]≤109)。

【输出格式】

每行一个整数表示答案。如果第i个告示没地方贴,输出-1。

【输入样例】

  1. 3 5 5
  2. 2
  3. 4
  4. 3
  5. 3
  6. 3

【输出样例】

  1. 1
  2. 2
  3. 1
  4. 3
  5. -1

【数据规模】

对于20%的数据,n=1。

对于40%的数据,n,m≤500。

对于70%的数据,n≤2000。

对于90%的数据,n≤50000。

对于100%的数据,n≤200000。

解析

用c[i]表示第i行还剩多少长度。

用线段树维护c[i]的区间最大值即可。

Code

  1. #include <algorithm>
  2. #include <iostream>
  3. #include <cstring>
  4. #include <string>
  5. #include <cstdio>
  6. #include <cmath>
  7. #include <queue>
  8. using namespace std;
  9. inline int read()
  10. {
  11. int num=0,w=1;
  12. char ch=getchar();
  13. while(ch<'0'||ch>'9')
  14. {
  15. if(ch=='-') w=-1;
  16. ch=getchar();
  17. }
  18. while(ch>='0'&&ch<='9')
  19. {
  20. num=(num<<1)+(num<<3)+ch-'0';
  21. ch=getchar();
  22. }
  23. return num*w;
  24. }
  25. int h,m,n,c[800100];
  26. int w;
  27. void build(int p,int l,int r)
  28. {
  29. c[p]=m;
  30. if(l==r) return ;
  31. int mid=(l+r)>>1;
  32. build(p*2,l,mid),build(p*2+1,mid+1,r);
  33. }
  34. int ask(int p,int l,int r)
  35. {
  36. if(l==r)
  37. {
  38. c[p]-=w;
  39. return l;
  40. }
  41. int mid=(l+r)>>1;
  42. if(c[p*2]>=w)
  43. {
  44. int temp=ask(p*2,l,mid);
  45. c[p]=max(c[p*2+1],c[p*2]);
  46. return temp;
  47. }
  48. else
  49. {
  50. int temp=ask(p*2+1,mid+1,r);
  51. c[p]=max(c[p*2+1],c[p*2]);
  52. return temp;
  53. }
  54. }
  55. int main()
  56. {
  57. //freopen("billboard.in","r",stdin);
  58. //freopen("billboard.out","w",stdout);
  59. h=read(),m=read(),n=read();
  60. build(1,1,h);
  61. for(int i=1;i<=n;i++)
  62. {
  63. w=read();
  64. if(w>c[1])
  65. {
  66. cout<<"-1"<<endl;
  67. continue;
  68. }
  69. cout<<ask(1,1,h)<<endl;
  70. }
  71. return 0;
  72. }
View Code

 

 

 

 

 

T4 种树

题目

【题目描述】

你要在一条无穷长的马路上种树。

你想种3种树,分别是草莓树,西瓜树,土豆树。

给定3个正整数A,B,C,你可以选择3个整数x,y,z,然后:

  • 在位置 … , x-2A , x-A , x , x+A , x+2A , … 分别种1棵草莓树。
  • 在位置 … , y-2B , y-B , y , y+B , y+2B , … 分别种1棵西瓜树。
  • 在位置 … , z-2C ,z-C , z , z+C , z+2C , … 分别种1棵土豆树。

你想要最大化最近的两棵树的距离,请你输出这个最大距离。

【输入格式】

每个测试点多组测试数据。

每组数据输入一行A,B,C。

没给出数据组数,你可以这样输入:

while (scanf(“%d%d%d”, &A, &B, &C) == 3)

{

       ……

}

【输出格式】

对于每个询问输出一行表示答案。

【输入样例】

  1. 1 5 8
  2. 3 3 6
  3. 2000 2000 2000
  4. 999 999 999
  5. 233 233 233
  6. 100 100 100
  7. 40 30 20

【输出样例】

  1. 0
  2. 1
  3. 666
  4. 333
  5. 77
  6. 33
  7. 5

【数据规模】

对于100%的数据,1≤A,B,C≤2000。

解析

先用solve函数求出三树两两之间最小距离的最小值,然后再找到最大的即可。

证明过程比较麻烦,本蒟蒻数论不太好,就不给出详细证明了。

Code

  1. #include <algorithm>
  2. #include <iostream>
  3. #include <cstring>
  4. #include <string>
  5. #include <cstdio>
  6. #include <cmath>
  7. #include <queue>
  8. using namespace std;
  9. int a,b,c,x,y,z,ans;
  10. int gcd(int x,int y)
  11. {
  12. if(y==0) return x;
  13. return gcd(y,x%y);
  14. }
  15. int solve(int a,int b,int x,int y)
  16. {
  17. int g=gcd(a,b);
  18. int t=(x-y)%g;
  19. if(t<0) t+=g;
  20. return min(t,g-t);
  21. }
  22. int main()
  23. {
  24. while(cin>>a>>b>>c)
  25. {
  26. ans=0;
  27. for(y=0;y<b;y++)
  28. for(z=0;z<c;z++)
  29. {
  30. int temp;
  31. temp=min(solve(a,b,0,y),min(solve(b,c,y,z),solve(a,c,0,z)));
  32. ans=max(ans,temp);
  33. }
  34. cout<<ans<<endl;
  35. }
  36. return 0;
  37. }
View Code

 

原文链接:http://www.cnblogs.com/I-Love-You-520/p/11619429.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号