先讲1007,有m个人,n种石头,将n种石头分给m个人,每两个人之间要么是朋友关系,要么是敌人关系,朋友的话他们必须有一种相同颜色的石头,敌人的话他们必须所有石头的颜色都不相同。另外,一个人可以不拥有任何一种石头。求m个人的所有关系是不是都能用n种石头表示出来。比赛当时找的关系是n种石头可以表示n+1个人的关系。但是一直WA,因为考虑不周。

  我们考虑这样的一种情况,我们把人分为左边和右边两部分,每边的人里面都互相为敌人,同时左边的任意一个人和右边的任意一个人都是朋友。举个例子,左边有3人,右边两人。考虑左边第一人,他和右边每一个人都要有相同的至少一种石头,那么他至少要有两种石头,而左边的每一个人的每一个石头都不能一样,那么至少要有3*2=6种石头。通过这个例子我们就可以找出规律来了,总共需要的石头量为左右人数之积。

  那么问题就转化成了,将m个人分成两组,使得乘积最大(这是m个人下的最坏的情况,如果这个情况都能满足,那么其他情况也都能满足了)。显然,将m个人均分一下得到的乘积最大,那么答案就出来了。

  代码如下:

 1 #include <stdio.h>
 2 #include <algorithm>
 3 #include <string.h>
 4 using namespace std;
 5 typedef long long ll;
 6
 7 int main()
 8 {
 9     int n,m;
10     while(scanf("%d%d",&n,&m)==2)
11     {
12         int l = n/2;
13         int r = n-n/2;
14         if(1LL*l*r > m) puts("F");
15         else puts("T");
16     }
17 }

View Code

  1006,当时比赛的时候是乱做弄出来的,只要满足下面3个条件即可:

  假设有n个队伍,

  1.每个队伍的分数都不能超过2*(n-1)。

  2.所有队伍的总分必须等于n*(n-1)。

  3.分数为奇数的队伍数必须是偶数个,每两个队伍之间都有一场平局。

  但是,题解给出的方法似乎是有一个定理的(Landau's Theorem)。

  先将分数从小到大排序一下,那么对任意前i个人的总分,必须不小于他们所能够得到的分数,即i*(i-1),同时总分必须是n*(n-1)。

  另外,如果没有平局,并且只是胜者获得1分,同样可以使用这个定理,只要改变前i个人所能获得的分数即可,即C(i,2),同时,总分也必须等于C(n,2)。

  1009,当时比赛的时候m的大小是5500,那么可以在数据规模较小的情况下暴力求补图,数据规模较大的时候找规律来做(因为数据规模较大的时候点数远远大于边数,那么一定是不止一个联通块,规律就是如果与s点相邻,距离就是2,因为可以先到另外一个联通块再到这个点来完成,如果不相邻距离就是1了,因为补图上直接可达)。现在m的数据范围变大了,得采用题解的方法,在补图上bfs。代码如下(直接看代码也是可以看懂的):

 1 #include <stdio.h>
 2 #include <algorithm>
 3 #include <string.h>
 4 #include <queue>
 5 #include <set>
 6 using namespace std;
 7 typedef long long ll;
 8 const int N = 200000 + 5;
 9
10 vector<int> G[N];
11 int n,m,s;
12 int dis[N];
13
14 void addEdge(int u,int v)
15 {
16     G[u].push_back(v);
17 }
18
19 void solve()
20 {
21     set<int> sa,sb;
22     // 每次扩展都是向不相邻的边扩展
23     // sb保存的是仍未bfs过的点
24     queue<int> Q;
25     for(int i=1;i<=n;i++) if(i!=s) sa.insert(i);
26     Q.push(s);
27     memset(dis,-1,sizeof(dis));
28     dis[s] = 0;
29     while(!Q.empty())
30     {
31         int x = Q.front();Q.pop();
32         for(int i=0;i<G[x].size();i++)
33         {
34             int v = G[x][i];
35             if(!sa.count(v)) continue;
36             sa.erase(v);
37             sb.insert(v);
38         }
39         for(set<int>::iterator it = sa.begin();it!=sa.end();it++)
40         {
41             dis[*it] = dis[x] + 1;
42             Q.push(*it);
43         }
44         sa.swap(sb);
45         sb.clear();
46     }
47     int fir = 0;
48     for(int i=1;i<=n;i++)
49     {
50         if(i!=s)
51         {
52             if(fir) printf(" ");
53             else fir = 1;
54             printf("%d",dis[i]);
55         }
56     }
57     puts("");
58 }
59
60 int main()
61 {
62     int T;scanf("%d",&T);
63     while(T--)
64     {
65         scanf("%d%d",&n,&m);
66         for(int i=1;i<=n;i++) G[i].clear();
67
68         for(int i=1;i<=m;i++)
69         {
70             int u,v;scanf("%d%d",&u,&v);
71             addEdge(u,v);
72             addEdge(v,u);
73         }
74
75         scanf("%d",&s);
76         solve();
77     }
78 }

View Code

  1008,题意是给一个区间L和R,求a[L]%a[L+1]%a[L+2]...%a[R]。

  一个性质:a%b,如果a小于b,那么a不变,否则,得到的数小于等于a/2(这个性质不知道要怎么证,不过似乎就是这样的样子- -)。

  那么每次取余以后都会减半,那么复杂度就是log级别的了。

  那么,我们每次找出[L+1,R]中第一个不比最左边的数大的数的位置,并不断的缩小区间即可。关于如何找,这里用了线段树来维护一个区间内的最小值,那么我们就可以用线段树找出我们需要的东西了~具体见代码:

 1 #include <stdio.h>
 2 #include <algorithm>
 3 #include <string.h>
 4 #include <queue>
 5 #include <set>
 6 #define t_mid (l+r >> 1)
 7 #define ls (o<<1)
 8 #define rs (o<<1 | 1)
 9 #define lson ls,l,t_mid
10 #define rson rs,t_mid+1,r
11 using namespace std;
12 typedef long long ll;
13 const int N = 100000 + 5;
14
15 int a[N],c[N<<2],n;
16 void build(int o,int l,int r)
17 {
18     if(l==r) {c[o] = a[l];return;}
19     build(lson);
20     build(rson);
21     c[o] = min(c[ls],c[rs]);
22 }
23
24 int query(int ql,int qr,int o,int l,int r,int x)
25 {
26     if(l==r)
27     {
28         if(c[o] <= x) return l;
29         else return -1;
30     }
31     int ans = -1;
32     if(t_mid >= ql && c[ls] <= x)
33     {
34         ans = query(ql,qr,lson,x);
35         if(ans == -1)
36         {
37             if(t_mid < qr && c[rs] <= x) ans = query(ql,qr,rson,x);
38         }
39         return ans;
40     }
41     else if(t_mid < qr && c[rs] <= x) return query(ql,qr,rson,x);
42     return -1;
43 }
44
45 int main()
46 {
47     int T;scanf("%d",&T);
48     while(T--)
49     {
50         scanf("%d",&n);
51         for(int i=1;i<=n;i++) scanf("%d",a+i);
52         build(1,1,n);
53
54         int q;scanf("%d",&q);
55         while(q--)
56         {
57             int ql,qr;scanf("%d%d",&ql,&qr);
58             int now = a[ql];
59             while(ql < qr)
60             {
61                 ql = query(ql+1,qr,1,1,n,now);
62                 if(ql == -1) break;
63                 now %= a[ql];
64             }
65             printf("%d\n",now);
66         }
67     }
68 }

线段树维护

当然,也可以使用单调栈来维护,代码如下(只有主程序部分的代码):

 1 int a[N],nxt[N];
 2 stack<int> s;
 3 int main(){
 4     int T,n,m,l,r;
 5     cin >> T;
 6     while(T --){
 7         memset(nxt,-1,sizeof(nxt));
 8         while(!s.empty()) s.pop();
 9         cin >> n;
10         for(int i = 1 ; i <= n ; i ++) scanf("%d",&a[i]);
11         cin >> m;
12         for(int i = 1 ; i <= n ; i ++){
13             // 单调递增的栈。
14             if(s.empty() || a[i] >= a[s.top()]) s.push(i);
15             else{
16                 while(!s.empty() && a[i] < a[s.top()]){
17                     nxt[s.top()] = i;
18                     s.pop();
19                 }
20                 s.push(i);
21             }
22         }
23         while(m --){
24             scanf("%d%d",&l,&r);
25             int ret = a[l] , tmp = l;
26             while(nxt[tmp] <= r && nxt[tmp] != -1){
27                 tmp = nxt[tmp];
28                 ret = ret % a[tmp];
29             }
30             cout << ret << endl;
31         }
32     }
33     return 0;
34 }

单调栈维护

  1010,直接dfs,我们在dfs的过程中,记录下各个数字出现的情况,然后遇到一个新的数字a[i]的时候,我们查找小于等于k/a[i]的数字有多少个就可以了(这就是对答案的贡献)。那么我们可以用树状数组或者线段树维护各个数字出现的情况以及区间和。另外这个dfs的过程遇到分支时,先让该位置的数字出现次数加1,回溯的时候再减掉就可以了。代码如下:

 1 #include <stdio.h>
 2 #include <algorithm>
 3 #include <string.h>
 4 #include <vector>
 5 using namespace std;
 6 const int N = (int)1e5+5;
 7 typedef long long ll;
 8
 9 int n,m;
10 ll k,ans;
11 ll a[N*2],b[N];
12 vector<int> G[N];
13 bool vis[N];
14 int c[N*2];
15
16 int getsum(int x)
17 {
18     int ret = 0;
19     while(x)
20     {
21         ret += c[x];
22         x -= (x&-x);
23     }
24     return ret;
25 }
26
27 void update(int x,int dt)
28 {
29     while(x <= m)
30     {
31         c[x] += dt;
32         x += (x&-x);
33     }
34 }
35
36 void dfs(int x)
37 {
38     int can = lower_bound(a+1,a+1+m,k/b[x]) - a;
39     // 之所以在main里面需要把k/a[i]都当作一个元素,是因为要避免在这里查找的时候出问题
40     // 比方说现在的b[x]是5,那么之前储存的数字中小于等于20的都是可以成立的,但是现在假设没有储存20这个数字,
41     // 那么lower_bound找到的是21,而如果21恰好有的话,那就出错了!(因为我们要的是<=20的数字的个数)
42     int pos = lower_bound(a+1,a+1+m,b[x]) - a;
43     ans += getsum(can);
44     update(pos,1);
45     for(int i=0;i<G[x].size();i++) dfs(G[x][i]);
46     update(pos,-1);
47 }
48
49 int main()
50 {
51     int T;scanf("%d",&T);
52     while(T--)
53     {
54         scanf("%d%I64d",&n,&k);
55         for(int i=1;i<=n;i++) G[i].clear();
56         memset(vis,false,sizeof(vis));
57         memset(c,0,sizeof(c));
58         ans = 0;
59
60         for(int i=1;i<=n;i++) {scanf("%I64d",a+i);b[i]=a[i];}
61         for(int i=1;i<n;i++)
62         {
63             int u,v;scanf("%d%d",&u,&v);
64             G[u].push_back(v);
65             vis[v] = true;
66         }
67
68         for(int i=1;i<=n;i++) a[i+n] = k/a[i];
69         sort(a+1,a+1+n*2);
70         m = unique(a+1,a+1+n*2) - (a+1);
71         for(int i=1;i<=n;i++)
72         {
73             if(!vis[i])
74             {
75                 dfs(i);
76                 break;
77             }
78         }
79         printf("%I64d\n",ans);
80     }
81 }

View Code

转载于:https://www.cnblogs.com/zzyDS/p/5861215.html

2016 ICPC 大连网络赛 部分题解相关推荐

  1. 2016 ICPC 北京网络赛 A 恶心模拟 F 循环矩阵,FFT(待补) I 模拟

    2016 ICPC 北京网络赛 A - The Book List 题意:每本书有所属种类,给出原生的存放方式,求按新的方式存放的样子. tags:坑到心态爆炸的题==  直接堆进vector里搞的, ...

  2. HDU 5869.Different GCD Subarray Query-区间gcd+树状数组 (神奇的标记右移操作) (2016年ICPC大连网络赛)...

    树状数组... Different GCD Subarray Query Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/6 ...

  3. HDU - 5875 2016 ACM/ICPC 大连网络赛 H题 暴力

    题目链接 题意:给你一个区间l,r一直将val[l]模上val[l+1],val[l+2]...val[r],因为一个模上比前一个数小数是没有意义的,所以需要将每一个点找到右边第一个小于他的点就行. ...

  4. HDU - 5876 Sparse Graph 2016 ACM/ICPC 大连网络赛 I题 bfs+set+补图最短路

    题目链接 题意:给的补图,让你求一个源点到其他点的最短距离,因为图太稠密了, 用dij以及spfa根本不得行,这里只能用一种我不会方法来进行,这里用了bfs的方法以及set来维护,分别set维护一个未 ...

  5. HDU - 5877 Weak Pair 2016 ACM/ICPC 大连网络赛 J题 dfs+树状数组+离散化

    题目链接 You are given a rootedrooted tree of NN nodes, labeled from 1 to NN. To the iith node a non-neg ...

  6. hdu 4001 (2011ACM/ICPC大连网络赛)

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=4001 题意不多解释,说说思路:按照长和宽排序,排序后,前面的方块一定不能叠放在后面的方块上,而后面的方块有 ...

  7. 2019 ACM - ICPC 上海网络赛 E. Counting Sequences II (指数型生成函数)

    繁凡出品的全新系列:解题报告系列 -- 超高质量算法题单,配套我写的超高质量题解和代码,题目难度不一定按照题号排序,我会在每道题后面加上题目难度指数(1∼51 \sim 51∼5),以模板题难度 11 ...

  8. 2019 ICPC 南昌网络赛 H. The Nth Item

    2019 ICPC 南昌网络赛 H. The Nth Item 题目大意:已知一个数列F(n): F(0)=0,F(1)=1 F(n)=3∗F(n−1)+2∗F(n−2),(n≥2) ​ 给你一个操作 ...

  9. 2019 ICPC 徐州网络赛 J.Random Access Iterator

    2019 ICPC 徐州网络赛 J.Random Access Iterator 题目大意:给你n个点和n-1条边(树形结构),保证1为根节点,通过以下方式dfs遍历: 询问dfs到最深节点的概率(有 ...

  10. 计蒜客 17115 2017 ICPC 西安网络赛 B Coin

    Problem nanti.jisuanke.com/t/17115 Reference 关于二项展开式系数和 [二项式定理][推导]计蒜客17115 2017 ACM-ICPC 亚洲区(西安赛区)网 ...

最新文章

  1. android xUtils的使用
  2. Vue.js框架简单读取数据库信息并渲染完成news新闻文章列表以及detail详情页功能(小试牛刀)
  3. c++ using namespace std; - 海明威 - 博客园
  4. 双系统用wmware挂载linux,安装Windows 和 Linux双系统(vmware) Centos7
  5. mysql根据某个字段的不同状态的值进行统计
  6. oracle联合主键怎么找,Oracle数据库联合主键
  7. Java笔记-JNI中Java与C语言解决中文乱码问题
  8. python 全部缩进一行_Python开发工具:缩进规则的使用
  9. 《文献检索》期末复习整理~2020
  10. r720换固态硬盘后如何重装系统_联想R720重装Winddows10无法识别固态硬盘咋办
  11. Vmplayer NAT模式下做端口映射
  12. java 控制台程序_控制台应用程序开发(C# 与 Java)
  13. 做到这几点在家也能拍出好看的证件照
  14. 关于本地磁盘“介质受写入保护”的解决
  15. ios录音文件路径_苹果6s的录音储存在哪个文件夹
  16. c语言数值常量4.5e0,c语言数值常量表示方法问题
  17. 什么是域名服务器作用是啥,域名服务器的作用是什么?域名服务器原理及流程...
  18. 客户端GUI测试技术和自动化测试架构设计简谈
  19. css设置表格自动换行;table换行无效
  20. 一分钟了解自动化测试 1

热门文章

  1. 2013 Multi-University Training Contest 1
  2. 数据分析之处理丢失数据
  3. 博客园 使用锚和书签制作目录
  4. miniMobile(手机)
  5. 如何用prometheus监控k8s集群中业务pod的metrics
  6. 你妈咪喊你回家刷题~~
  7. Kotlin基础-对象声明和表达式
  8. 漏洞扫描产品评测打分项
  9. Navicat连接CentOS7中的MariaDB
  10. 第05课 Linux命令初探(一)