Codeforces #447 Div.2 Tutorial
Problem A:QAQ
给一个字符串,求出可非连续的QAQ序列有多少个。
Analysis:比较水的一道题,记录每一个Q的位置,预处理A的个数即可
然而还是fst了,原因是未考虑一个Q都没有的极端情况,导致vector().size-1溢出!
以后一定要注意,当对unsigned int类型的vector().size作减法时考虑是否可能出现负数情况
- #include <bits/stdc++.h>
- using namespace std;
- int cnt[];
- string s;
- vector<int> q;
- int main()
- {
- cin >> s;
- for(int i=;i<s.size();i++)
- {
- cnt[i+]=cnt[i];
- if(s[i]=='A') cnt[i+]++;
- else if(s[i]=='Q') q.push_back(i+);
- }
- if(!q.size()) cout << ,return ; //对极端情况要特殊考虑
- //因为vector.size()是unsigned int,减1时会溢出
- int res=;
- for(int i=;i<q.size()-;i++)
- for(int j=i+;j<q.size();j++)
- {
- int x=q[i],y=q[j];
- res+=(cnt[y]-cnt[x]);
- }
- cout << res;
- return ;
- }
Problem A
Problem B:Ralph and his magic field
喜闻乐见的组合数学题,可划归为:在一个n*m的表格上填0和1,问在每行每列的和均为奇数或偶数时总方案数为多少
Analysis:一道比较考思维的题目,而思维能力不足一直我的弱项
其实看到n,m为1e18就知道是结论题,这时候推不出来暴力打表找规律也行啊,以后还是要灵活一些
正解就是把问题转换成(n-1)*(m-1)的全排列问题,最后的一行一列根据最终要求推出来就行了
但要注意的是,当要求为奇数,且n、m奇偶性不同时,方案数为0
(证明:1、反证法:只看横行为偶数个奇数,只看竖行为奇数个奇数,但总和不应有变,矛盾
2、利用(n-1)*(m-1)的矩形来证明:在(n-1)*(m-1)表上均为1时,最后一行和最后一列奇偶性必然不同,而每将1个1变为0,两边的奇偶性都不会变为相同)
至于求2^(n-1)^(m-1)就没什么好讲的了,只要注意快速幂必须分两次求,否则(n-1)*(m-1)会爆long long
- #include <bits/stdc++.h>
- using namespace std;
- const int MOD=;
- long long n,m;
- int k;
- long long quick_pow(long long a,long long b)
- {
- long long base=a,res=;
- while(b)
- {
- if(b%) res=res*base%MOD;
- b>>=;
- base=base*base%MOD;
- }
- return res;
- }
- int main()
- {
- cin >> n >> m >> k;
- if(k==- && (n%!=m%)) cout << ;
- else cout << quick_pow(quick_pow(,n-),m-);
- return ;
- }
Problem B
Problem C:Marco and GCD Sequence
这次中国选手出题就变成数学大赛了啊(雾
给定有序集合S,S是由一个n个元素组成的序列中对于每个1 ≤ i ≤ j ≤ n计算出的gcd(ai, ai + 1, ..., aj)产生的,输出你构造的序列,如没有输出-1
Analysis:又是一道思维题
我当时的想法是既然序列中的数肯定都属于S,且S中的最后一个数必选,那从后往前贪心选取不就行了。当时写起来便很虚,其实明显是有bug的,因为没有想到普遍构造
对于这类构造题,首先可以想一想如果将条件变强,是否存在一种通解
对于本题而言,便猜想如果s1,s2,s3.......sn均为s1,即gcd(a1,a2....an)的倍数时,便可将序列构造为s1,s2,s1,s3,s1,s4,s1,s5.....s1,sn
那如果s1不是s1,s2,s3....sn的公约数呢?那便可证明不存在这样的序列,因为a1,a2....an的最大公约数便是s1。
对于此题,我只想到S中的最后一个数必然为an,却未想到S1必然是a1,a2,a3.....an的最大公约数
对这类序列区间求值后统一排序的题目首尾均是关键
其次,在发现线性算法无法很好解决时,考虑对特定情况下的构造,再进行推广
- #include <bits/stdc++.h>
- using namespace std;
- int m,dat[];
- int gcd(int a,int b)
- {
- if(a%b==) return b;
- else return gcd(b,a%b);
- }
- int main()
- {
- cin >> m;
- for(int i=;i<=m;i++) cin >> dat[i];
- if(m==)
- {
- cout << << endl << dat[];
- return ;
- }
- int all=dat[];
- for(int i=;i<=m;i++) all=gcd(all,dat[i]);
- if(all!=dat[]) cout << -;
- else
- {
- cout << *(m-) << endl;
- for(int i=;i<=m;i++) cout << dat[] << " " << dat[i] << " ";
- }
- return ;
- }
Problem C
Problem D:Ralph And His Tour in Binary Country
给定一棵树,每次给1个点A,求到A的距离不超过H的点到A的距离和
Analysis:这道题一开始以为要树剖,结果发现并不用
在每一颗子树下,可以预处理出子树下所有点到子树根节点的距离及前缀和,从而O(logn)求出该子树下到子树根节点距离不超过H-x的和
因此,我们可以从A节点开始,一层层向上遍历,找父亲,直到距离已超过H,每次求出当前子树下到子树根节点B距离不超过H-x(A到B的距离)的和
但这样明显会有一定的重复计算,因此每次我们找到父亲后,只能查找该父亲下的另一棵子树
这时实现时有一些小技巧:1、当数据在节点时可以递归建树时。但当数据在边上时,应当以边为线索进行建树
2、树上的遍历为保证不重复,只要每次记录上一次操作的last节点,保证不重复计算
3、找到边与点的关系,在本题中,第i个点到其父节点的边为Ei-1
- #include <bits/stdc++.h>
- using namespace std;
- typedef long long ll;
- const int MAXN=;
- int n,m,len[MAXN],A,H,t[MAXN];
- vector<int> a[MAXN];
- vector<ll> pre[MAXN];
- inline int read() //OI优化标准模块,专防卡常
- {
- char ch;int num,f=;
- while(!isdigit(ch=getchar())) f|=(ch=='-');
- num=ch-'';
- while(isdigit(ch=getchar())) num=num*+ch-'';
- return f?-num:num;
- }
- inline void write(ll x)
- {
- if(x<) putchar('-'),x=-x;
- if(x>) write(x/);
- putchar(x%+'');
- }
- void merge(int x,int y) //类似于归并排序的操作
- {
- int lx=a[x].size(),ly=a[y].size(),d=len[y-];
- int k=,p=,q=;
- while(p<lx && q<ly)
- {
- if(a[x][p]<a[y][q]+d) t[k++]=a[x][p],p++;
- else t[k++]=a[y][q]+d,q++;
- }
- while(p<lx) t[k++]=a[x][p],p++;
- while(q<ly) t[k++]=a[y][q]+d,q++;
- a[x].clear();
- for(int i=;i<k;i++) a[x].push_back(t[i]);
- }
- ll cal(int node,ll tar)
- {
- ll ret=;
- ll pos=lower_bound(a[node].begin(),a[node].end(),tar)-a[node].begin()-;
- ret=tar*(pos+)-pre[node][pos];
- return ret;
- }
- ll BinaryCount(int node)
- {
- ll res=,t=H,last=node; //last保证不重复计算
- res+=cal(node,t);t-=len[node-];node>>=; //先加上当前节点
- while(node> && t>)
- {
- res+=t; //加上当前的根节点
- int lch=(node<<),rch=((node<<)|); //处理当前根节点下的子节点
- if(lch<=n && lch!=last && t-len[lch-]>) res+=cal(lch,t-len[lch-]);
- if(rch<=n && rch!=last && t-len[rch-]>) res+=cal(rch,t-len[rch-]);
- last=node;t-=len[node-];node>>=;
- }
- return res;
- }
- int main()
- {
- cin >> n >> m;
- for(int i=;i<=n-;i++) len[i]=read();
- for(int i=;i<=n;i++) a[i].push_back();
- for(int i=n;i>;i--) merge(i/,i); //以边为线索进行更新
- for(int i=;i<=n;i++) //对前缀和的预处理
- for(int j=;j<a[i].size();j++)
- if(!j) pre[i].push_back(a[i][j]);
- else pre[i].push_back(pre[i][j-]+a[i][j]);
- for(int i=;i<=m;i++)
- {
- cin >> A >> H;
- write(BinaryCount(A));cout << endl;
- }
- return ;
- }
Problem D
Problem E:Ralph and Mushrooms
Analysis:莫名其妙,E题成了道简单题
主要就是先Tarjan缩点,在每一个强联通分量里对数据进行特殊计算
接下来在DAG上求最长路
注意,此题的起点不一定入度为零,因此不能直接拓扑排序,应记忆化搜索
Tips:1、对(n-1)+(n-2)+(n-3)+(n-4)......(n-k)的计算是一个难点,标算的数学计算法还没看懂......
2、对于DAG的处理:不一定非要拓扑+DP,可以直接记忆化搜索,但要注意的是此时维护的是到终止节点的最大距离
3、Tarjan缩点后重新建图时,可以不用处理两个节点间的多条边
- #include <bits/stdc++.h>
- using namespace std;
- typedef pair<int,int> P;
- const int N=;
- int n,m,st,low[N],dfn[N],time_point=,col[N],cnt=;
- bool vis[N],instack[N];
- long long res=,tot[N],dp[N];
- inline int read()
- {
- char ch;
- while(!isdigit(ch=getchar()));
- int num=ch-'';
- while(isdigit(ch=getchar())) num=num*+ch-'';
- return num;
- }
- struct ed
- {
- int x,y,w;
- }edge[N];
- vector<P> a[N];
- stack<int> s;
- void tarjan(int cur) //Tarjan模板
- {
- time_point++;
- dfn[cur]=low[cur]=time_point;
- vis[cur]=true;
- instack[cur]=true;
- s.push(cur);
- for(int i=;i<a[cur].size();i++)
- {
- int u=a[cur][i].first;
- if(!vis[u])
- {
- tarjan(u);
- low[cur]=min(low[cur],low[u]);
- }
- else if(instack[u])
- {
- low[cur]=min(low[cur],low[u]);
- }
- }
- if(dfn[cur]==low[cur])
- {
- cnt++;int t;
- do
- {
- t=s.top();s.pop();
- instack[t]=false;
- col[t]=cnt;
- }while(t!=cur);
- }
- }
- long long cal(int t) //标算的数学计算法
- {
- long long k=(long long)(sqrtl((long double)t*+0.25)-0.5);
- return (k*(*t-(k+)*(k+)))/+t;
- }
- void dfs(int node) //记忆化
- {
- if(dp[node]) return;
- for(int i=;i<a[node].size();i++)
- {
- int v=a[node][i].first;
- dfs(v);
- dp[node]=max(dp[node],dp[v]+a[node][i].second); //维护到终止点的值
- }
- dp[node]+=tot[node]; //在完结后才加上当前节点的值
- }
- int main()
- {
- n=read();m=read();
- for(int i=;i<=m;i++)
- {
- edge[i].x=read();edge[i].y=read();edge[i].w=read();
- a[edge[i].x].push_back(P(edge[i].y,edge[i].w));
- }
- st=read();
- tarjan(st);
- for(int i=;i<N;i++) a[i].clear();
- for(int i=;i<=m;i++) //对缩点后每一个点的数据更新
- {
- int u=edge[i].x,v=edge[i].y;
- if(col[u]==col[v])
- {
- tot[col[u]]+=cal(edge[i].w);
- }
- }
- for(int i=;i<=m;i++)
- {
- int u=edge[i].x,v=edge[i].y; //这里可以不用考虑两个点间有多条边的情况
- if(col[u]!=col[v])
- {
- a[col[u]].push_back(P(col[v],edge[i].w));
- }
- }
- dfs(col[st]);
- cout << dp[col[st]];
- return ;
- }
Problem E
Codeforces #447 Div.2 Tutorial的更多相关文章
- Codeforces #344 Div.2
Codeforces #344 Div.2 Interview 题目描述:求两个序列的子序列或操作的和的最大值 solution 签到题 时间复杂度:\(O(n^2)\) Print Check 题目 ...
- Codeforces #345 Div.1
Codeforces #345 Div.1 打CF有助于提高做题的正确率. Watchmen 题目描述:求欧拉距离等于曼哈顿距离的点对个数. solution 签到题,其实就是求有多少对点在同一行或同 ...
- Codeforces Beta Round #27 (Codeforces format, Div. 2)
Codeforces Beta Round #27 (Codeforces format, Div. 2) http://codeforces.com/contest/27 A #include< ...
- Codeforces#441 Div.2 四小题
Codeforces#441 Div.2 四小题 链接 A. Trip For Meal 小熊维尼喜欢吃蜂蜜.他每天要在朋友家享用N次蜂蜜 , 朋友A到B家的距离是 a ,A到C家的距离是b ,B到C ...
- codeforces #592(Div.2)
codeforces #592(Div.2) A Pens and Pencils Tomorrow is a difficult day for Polycarp: he has to attend ...
- codeforces #578(Div.2)
codeforces #578(Div.2) A. Hotelier Amugae has a hotel consisting of 1010 rooms. The rooms are number ...
- codeforces #577(Div.2)
codeforces #577(Div.2) A Important Exam A class of students wrote a multiple-choice test. There are ...
- codeforces #332 div 2 D. Spongebob and Squares
http://codeforces.com/contest/599/problem/D 题意:给出总的方格数x,问有多少种不同尺寸的矩形满足题意,输出方案数和长宽(3,5和5,3算两种) 思路:比赛的 ...
- Codeforces Round #447 (Div. 2) B. Ralph And His Magic Field 数学
题目链接 题意:给你三个数n,m,k;让你构造出一个nm的矩阵,矩阵元素只有两个值(1,-1),且满足每行每列的乘积为k,问你多少个矩阵. 解法:首先,如果n,m奇偶不同,且k=-1时,必然无解: 设 ...
随机推荐
- Linux 中使用 dd 测试磁盘性能
翻译自 : Linux I/O Performance Tests using dd 基本说明 dd 可以用来做简单的低级别复制文件. 这样做, 一般都是可一直直接访问设备文件. 需要说明的是, 错误 ...
- 聂老师的考验(反向bfs)
题目链接:http://113.240.233.2:8081/JudgeOnline/problem.php?id=1121 这个题看起来要多次使用bfs,其实只要换个思维就会发现这就是一个简单的bf ...
- C# SuperSocket 消息推送
服务端使用Nuget引用SuperSocket.WebSocket和SuperSocket.Engine 服务器端代码[控制台] using SuperSocket.WebSocket; using ...
- End to End Sequence Labeling via Bidirectional LSTM-CNNs-CRF论文小结
本篇论文是卡内基梅隆大学语言技术研究所2016年 arXiv:1603.01354v5 [cs.LG] 29 May 2016 今天先理解一下这个是什么意思: 找到的相关理解:arXi ...
- Linux内核堆栈使用方法 进程0和进程1【转】
转自:http://blog.csdn.net/yihaolovem/article/details/37119971 目录(?)[-] 8 Linux 系统中堆栈的使用方法 81 初始化阶段 82 ...
- Yii 1.1.17 二、Gii创建后台与后台登录验证
一.用Gii创建后台模块 1.启用gii,在config/main.php 'gii' => array( 'class' => 'system.gii.GiiModule', 'pass ...
- WAMP Apache 2.5 配置虚拟主机
1.在 Apache 的安装目录下 conf/httpd.conf 文件中搜索 hosts,去掉 Include 前面的 “#” 号后,即可启用虚拟主机. # Virtual hosts #Inclu ...
- 64_c1
CBFlib-0.9.5.15-3.fc26.i686.rpm 05-Feb-2017 21:55 427710 CBFlib-0.9.5.15-3.fc26.x86_64.rpm 05-Feb-20 ...
- socket.io入门整理
我自己在用socket.io开发,对官方网站上的文档,进行简单的整理,然后自己写了一个简单的聊天程序. 最最开始 先安装socket.io: 1 npm install socket.io 利用Nod ...
- 2017多校第8场 HDU 6143 Killer Names 容斥,组合计数
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6143 题意:m种颜色需要为两段长度为n的格子染色,且这两段之间不能出现相同的颜色,问总共有多少种情况. ...