Codeforces Round #266 (Div. 2)(解题报告)
来源:互联网 发布:asphalt 8 windows 10 编辑:程序博客网 时间:2024/06/06 17:27
题目:Round #266 (Div. 2)
A. Cheap Travel(水题)
题意:坐地铁,每次价格是a,有一种特殊票,每张价格为b,可以坐m次。求问坐n次的最少花费。
做法一般是两种,一种是直接枚举b的张数,取最小值,简单粗暴但有效,题目数据量不大。
当然,分析一下就可以发现,如果a*m > b,那么当次数有m次时,肯定是b划算。否则就全部买a的。
而如果买了多次b的之后,剩下n%m次不够买一次b,这时再判断下a*(n%m) 跟b的大小即可得到答案。
#include<cstdio>int main(){ int n, m, a, b; while(~scanf("%d %d %d %d", &n, &m, &a, &b)){ if(a*m > b){ int ans = (n/m)*b; n%=m; if(n*a <= b) ans += n*a; else ans += b; printf("%d\n", ans); } else{ printf("%d\n", n*a); } } return 0;}
B. Wonder Room(枚举)
题意:一个房间要容纳n个人,每个人要至少占用6平方米,现在房间是a*b大小,可以对a和b分别增大,问增大后能满足条件的房间的最小面积是多少。
根据题意可知房间最小面积是6*n,如果一开始a*b就大于等于6*n,不用修改直接输出答案。
对于要修改的,我是枚举a的大小,根据a求出b的最小长度,再算面积取最小值。
但是由于n<=10^9,全部枚举会超时,而当a超过sqrt(6*n)时,其实这时候b是很小的,所以当a超过sqrt(6*n),反过来就去枚举b。
枚举量最多就是2*sqrt(6*n)。
枚举的时候注意a和b不能比原来小就可以。
#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>using namespace std;typedef long long LL;int main(){ LL n, a, b, c, A, B; while(~scanf("%I64d %I64d %I64d", &n, &a, &b)){ n*=6; if(a*b>=n){ printf("%I64d\n%I64d %I64d\n", a*b, a, b); } else{ LL m = (LL)sqrt(n+0.1); LL ans = 0x7fffffffffffffffLL; for(LL i=a; i<=m && ans>n; i++){ if(n%i==0) c = n/i; else c = n/i + 1; if(c>=b){ if(i*c<ans){ ans = i*c; A = i; B = c; } } } for(LL i=b; i<=m && ans>n; i++){ if(n%i==0) c = n/i; else c = n/i + 1; if(c>=a){ if(i*c<ans){ ans = i*c; A = c; B = i; } } } printf("%I64d\n%I64d %I64d\n", ans, A, B); } } return 0;}
C. Number of Ways(前缀和,扫描)
题意:给定N个数的序列,对于2<=i<=j<=n-1,求出有多少组(i,j)满足sum[1, i-1],sum[i,j], sum[j+1, n]三段的和都相等。
因为三段加起来就是原来所有数的和,所以如果原先的和S不能被3整除,答案就是0,否则每段的和都应该是S/3。
我的做法是先从后往前叠加,我们先找个f[i],如果sum[i, n]等于S/3,那么标记f[i]为1,否则为0。
而cnt[i] = cnt[i+1] + f[i]。
然后再从前往后叠加,遇到sum[1, i]等于S/3的,就把cnt[i+2]加到答案。此时相当于到i为止作为第一段,然后在i+2到n里面寻找第三段的开始,剩下的就是第二段。
后来看了别人的代码,其实一次扫就可以,从左往右如果遇到sum[1, i]等于S/3的,就记录cnt[i] = cnt[i-1]+1,否则cnt[i]=cnt[i-1],遇到sum[1,i]等于S/3*2的,就把cnt[i-2]加进答案。思想还是一样的。
我的代码还是按照第一种做法来,即两边扫。
#include<cstdio>#include<cstring>typedef long long LL;const int N = 500010;int n;LL a[N];int cnt[N];int main(){ while(~scanf("%d", &n)){ LL sum = 0; memset(cnt, 0, sizeof(cnt)); for(int i=1; i<=n; i++){ scanf("%I64d", a+i); sum += a[i]; } if(sum%3!=0){ puts("0"); continue; } LL x = sum/3; LL y = 0; for(int i=n; i>0; i--){ y += a[i]; cnt[i] = cnt[i+1]; if(y==x) cnt[i]++; } LL ans = 0; sum = 0; for(int i=1; i<=n; i++){ sum += a[i]; if(sum==x){ ans += cnt[i+2]; } } printf("%I64d\n", ans); } return 0;}
D. Increase Sequence(dp)
题意:题目描述一种对序列的操作,对于给定的[l, r],一次操作表示这个区间的值全部加上1。可以有多次操作,唯一的限制是对于任意的[li, ri]和[lj, rj],li!=lj, ri!=rj。
问的是有多少种方案使得所有数字都变成给定的h。两种方案只要有一个操作区间不同,就算不同方案,当然区间的操作顺序是无关的。
首先还是把明显不可达的情况去掉,如果序列当中已经有数字大于h了,肯定没有方案,输出0。
接下来就是dp的时候了。
dp[i][j]表示到第i个数字为止,1~i所有数字都变成h,并且此时还有j个区间覆盖到,即还要往后面作用。
那么,对于a[i],计算d=h-a[i],说明要有d个区间覆盖到a[i],有两种状态转移过来:
一种是直接前面的dp[i-1][d]过来,a[i]这里不增加新区间。
另一种当然就是前面的dp[i-1][d-1]过来,a[i]再增加新区间。
所以dp[i] = dp[i-1][d] + dp[i-1][d-1]。
然后,由于我们可以选择在a[i]这里结束一个区间,有d个区间可以选择,所以还有dp[i][d-1] = dp[i][d] * d。
最后的答案就是dp[n][0],表示所有数字都变成h,而且操作的区间都结束掉了。
初始状态dp[0][0]=1,其它清0。
#include<cstdio>#include<cstring>typedef long long LL;const int mod = 1000000007;int n, h, a[2001];LL dp[2001][2000];int main(){ while(~scanf("%d %d", &n, &h)){ bool flag = 0; for(int i=1; i<=n; i++){ scanf("%d", a+i); if(a[i]>h) flag = 1; } if(flag){ puts("0"); continue; } memset(dp, 0, sizeof(dp)); dp[0][0] = 1; for(int i=1; i<=n; i++){ int d = h-a[i]; dp[i][d] = dp[i-1][d]; if(d){ dp[i][d] = (dp[i][d] + dp[i-1][d-1])%mod; dp[i][d-1] = dp[i][d] * d % mod; } } printf("%I64d\n", dp[n][0]); } return 0;}
E. Information Graph(并查集+lca+离线处理)
题意:n个员工,一开始没有上下关系。然后m次询问,询问分三种:
1 x y,y成为x的上司,题目保证在此之前x没有上司。
2 x,给x一份文档,他签名,然后给他的上司签名,上司签完再给上司的上司,直到没有上司了。
3 x i,询问x是否给编号i的文档签过名。文档编号是按照询问2出现的顺序从1开始标的。
昨晚做的时候考虑欠缺,system test挂掉了。
由于上下关系只有添加没有删减,所以我们可以先把所有询问读进来,顺便把上下关系构建起来。这种关系构成的可能是树,也可能是森林,我们可以增加一个虚拟节点0,让那些还没上司的当0为上司,这样就转化成树了。
完成之后我们才正式来处理m个询问。
那么,对于一份由x开始签名的文档,如果y签过名,y肯定在x向根走的路径上,y必须是x的祖先。所以用lca(y, x)是否等于y来做这个判断。
但是这里有一个问题,如果y是x签过某份文档之后,再成为x的上司,y是不会签到这份文档的。处理也很简单,增加个并查集,判断下他们在文档签完名是否已经在同一组即可。
另外,由于文档签名了之后信息是不会改变的,所以每处理一个询问2,就顺便把对应该文档的询问3处理掉,这样也不用担心y在x签完文档之后才成为x的上司的问题。
最后再按询问的顺序把询问3输出。
#include<cstdio>#include<cstring>#include<vector>#include<algorithm>using namespace std;const int LOG = 20;const int N = 100010;#define pb push_backstruct Query{ int id, x; Query(){} Query(int id, int x):id(id),x(x){}};vector<Query> Q[N];vector<int> V[N];inline void in(int &x){ x=0; char c=getchar(); while(c<48 || c>57) c=getchar(); while(c>=48 && c<=57){ x = x*10+c-48; c = getchar(); }}int n, m, q;int t[N], x[N], y[N], ans[N], f[N];int find(int X){ int Y = X; for(; X!=f[X]; X=f[X]); return f[Y]=X;}bool mk[N];int parent[LOG][N];int depth[N];void dfs(int x, int p, int d){parent[0][x] = p;depth[x] = d;for(int i=0; i<V[x].size(); i++){if(V[x][i] != p)dfs(V[x][i], x, d+1);}}void init(){ for(int i=1; i<=n; i++){ if(mk[i]){ V[0].pb(i); } } dfs(0, -1, 0); for(int k=0; k+1<LOG; k++){for(int i=0; i<=n; i++){if(parent[k][i]<0)parent[k+1][i] = -1;elseparent[k+1][i] = parent[k][parent[k][i]];}}}int lca(int u, int v){if(depth[u] > depth[v]) swap(u, v);for(int k=0; k<LOG; k++){if((depth[v]-depth[u]) >> k&1){v = parent[k][v];}}if(u==v)return u;for(int k=LOG-1; k>=0; k--){if(parent[k][u] != parent[k][v]){u = parent[k][u];v = parent[k][v];}}return parent[0][u];}int main(){ in(n); in(m); q = 0; int c = 0; for(int i=1; i<=n; i++) mk[i] = 1; for(int i=0; i<m; i++){ in(t[i]); in(x[i]); if(t[i]!=2) in(y[i]); else y[i]=++c; if(t[i]==1){ V[y[i]].pb(x[i]); mk[x[i]] = 0; } else if(t[i]==3){ Q[y[i]].pb(Query(++q, x[i])); } } for(int i=1; i<=n; i++){ f[i]=i; } init(); for(int i=0; i<m; i++){ if(t[i]==1){ f[x[i]] = y[i]; } else if(t[i]==2){ int p = find(x[i]); for(int j=0; j<Q[y[i]].size(); j++){ Query &qu = Q[y[i]][j]; int k = find(qu.x); if(k!=p || lca(qu.x, x[i])!=qu.x){ ans[qu.id] = 0; } else{ ans[qu.id] = 1; } } } } for(int i=1; i<=q; i++) puts(ans[i]?"YES":"NO"); return 0;}
- Codeforces Round #266 (Div. 2)解题报告
- Codeforces Round #266 (Div. 2)(解题报告)
- Codeforces Round #149 (Div. 2)解题报告
- Codeforces Round #180 (Div. 2) 解题报告
- Codeforces Round #190 (Div. 2) 解题报告
- Codeforces Round #191 (Div. 2) 解题报告
- Codeforces Round #189 (Div. 2) 解题报告
- Codeforces Round #142 (Div. 2) 解题报告
- Codeforces Round #229 (Div. 2) 解题报告
- Codeforces Round #241 (Div. 2) 解题报告
- Codeforces Round #262 (Div. 2)解题报告
- Codeforces Round #267 (Div. 2) 解题报告
- Codeforces Round #268 (Div. 2) 解题报告
- Codeforces Round #271 (Div. 2) 解题报告
- Codeforces Round #274 (Div. 2) 解题报告
- Codeforces Round #276 (Div. 2) 解题报告
- Codeforces Round #277 (Div. 2) 解题报告
- Codeforces Round #224 (Div. 2)解题报告
- 感受到Linux世界的善意了!python-scapy
- 字符串进行压缩
- sql
- JDBC读写mysql总结
- java中反射系列一
- Codeforces Round #266 (Div. 2)(解题报告)
- excel导入mysql数据库中
- “Nonparametric Blind Super-Resolution”
- 算法学习之排序算法:归并排序
- android source code online
- 2014.09.13 周六-html-xhtml-正则表达式-html总结-css
- 广岛上空的蘑菇云
- 我们在过去的时光里找到了什么
- 编程之所见