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时,必然无解: 设 ...
随机推荐
- UIView显示时遮挡导航栏的方法
[self.navigationController.view:addSubview];
- fs.createReadStream(filepath).pipe(response);这句是什么意思?
'use strict'; var fs = require('fs'), url = require('url'), path = require('path'), http = require(' ...
- 往Layout中动态添加View
需要注意几个方法:基本上所有的方法参数单位是px 1.设置View的宽高: LinearLayout.LayoutParams params = new LinearLayout().LayoutPa ...
- Linux简介——(一)
1. 常见操作系统 - 服务端操作系统 : linux.unix.windows server - 单机操作系统 : windows(dos .ucdos.win95.win98.win2000.xp ...
- python基础===进程,线程,协程的区别(转)
本文转自:http://blog.csdn.net/hairetz/article/details/16119911 进程拥有自己独立的堆和栈,既不共享堆,亦不共享栈,进程由操作系统调度. 线程拥有自 ...
- Tabular DataStream protocol 协议
Tabular DataStream protocol 协议 Freetds 创建过程 https://wenku.baidu.com/view/2076cbfaaef8941ea76e0576.ht ...
- VPS L2TP配置
原文地址:https://raymii.org/s/tutorials/IPSEC_L2TP_vpn_with_Ubuntu_14.04.html 只要保证ipsec verify没错,基本都可以成功 ...
- [session篇]看源码学习session(一)
假如你是使用过或学习过PHP,你一定觉得很简单.session只不过是$_SESSION就可以搞得,这还不简单只是对一个key-value就能工作了.我觉得可以大多数的phper都是这样的,这是语言本 ...
- Java中volatile修饰符,不稳定标记的用法笔记
今天学java特性时,发现了volatile修饰符,这个修饰符修饰的变量告诉java编译器忽略优化机制,这样的优势是: java优化后,寄存器会缓存内存里的变量,另一个线程修改这个变量的内存时,不会同 ...
- 高德地图web 端智能围栏
最近有个项目,需要在web上批量给设备设置智能围栏,设备超出范围报警,查看高德地图webJS API,web端操作案例如,后台判断没有提供源码 <!-- 重点参数:iconStyle --> ...