2016 China-Final 解题报告
来源:互联网 发布:java web书籍推荐 编辑:程序博客网 时间:2024/04/29 23:43
这几天又把China-Final的题补了一些,比较蛋疼的是为啥根本搜不到题解。。。我觉得我要多加些关键字,2016 ICPC China-Final, codeforces gym101194。题目在cf可以交,因为只有PDF就不每一题都加链接了。http://codeforces.com/gym/101194
A. Number Theory Problem
7的二进制表示为111,所以111, 1110(111移位的结果)都能被7整除。而
#include <bits/stdc++.h>using namespace std;typedef long long ll;typedef pair<int,int> PII;int main(){ int T,n; scanf("%d",&T); for (int t=1;t<=T;t++) { scanf("%d",&n); printf("Case #%d: %d\n",t,n/3); } return 0;}
C. Mr. Panda and Strips
这题据说比赛的时候
我最开始看到的是出题人的题解,消化了很久并且按照他讲的写了,结果WA了以后仔细改了改又TLE了。然后再回去看他的题解,感觉错误不止一个啊。。。= =
我出于无奈只好直接问q巨要了一份代码。。。
//By quailty, contest: 2016-2017 ACM-ICPC CHINA-Final, problem: (C) Mr. Panda and Strips, Accepted, ##include<cstdio>#include<cstring>#include<cstdlib>#include<cmath>#include<iostream>#include<algorithm>#include<set>using namespace std;const int MAXN=1005;const int MAXV=100005;int c[MAXN],r[MAXN];bool vis[MAXV];vector<int>loc[MAXV];set<pair<int,int> >st;multiset<int>len;inline int getMax(){ return (len.empty() ? 0 : *(--len.end()));}inline void setBlock(int x){ auto itr=st.lower_bound(make_pair(x+1,0)); if(itr==st.begin())return; itr--; int ml=x,mr=x; while(1) { if(itr->second<x)break; len.erase(len.lower_bound(itr->second-itr->first+1)); ml=min(ml,itr->first); mr=max(mr,itr->second); if(itr==st.begin()) { st.erase(itr); break; } else st.erase(itr--); } if(ml<x && st.find(make_pair(ml,x-1))==st.end()) st.insert(make_pair(ml,x-1)),len.insert(x-ml); if(mr>x && st.find(make_pair(x+1,mr))==st.end()) st.insert(make_pair(x+1,mr)),len.insert(mr-x);}int main(){ int T; scanf("%d",&T); for(int ca=1;ca<=T;ca++) { int n; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&c[i]); loc[c[i]].push_back(i); } for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++)vis[c[j]]=0; r[i]=i-1; while(r[i]<n && !vis[c[r[i]+1]])vis[c[++r[i]]]=1; } int res=0; for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++)vis[c[j]]=0; st.clear(),len.clear(); for(int j=i+1;j<=n;j++) { st.insert(make_pair(j,r[j])); len.insert(r[j]-j+1); } res=max(res,getMax()); for(int j=i;j>=1;j--) { if(vis[c[j]])break; vis[c[j]]=1; for(int k=0;k<(int)loc[c[j]].size();k++) if(loc[c[j]][k]>i)setBlock(loc[c[j]][k]); res=max(res,getMax()+(i-j+1)); } } printf("Case #%d: %d\n",ca,res); for(int i=1;i<=n;i++) loc[c[i]].clear(); } return 0;}
这个代码的意思大概就是先预处理每个颜色分布在哪几个位置,每个位置最多能延伸的区间。然后枚举第一个区间的右边界multiset<int> len
是辅助的保存长度的有序列。
这个算法对于每一个
后来又看到一份代码(是cf上的vj号交的,所以也不知道是哪位大侠)感觉很不错,跟这个其实是一个思路的,于是就学习了一下。
预处理时采用了时间戳的int数组,也可以像上面那样每次清空bool数组。
#include <bits/stdc++.h>using namespace std;typedef pair<int,int> PII;const int N=1005,MAX=1e5+5;vector<int> p[MAX];int a[N],dp[N][N];bool isok[N][N];int vis[MAX];set<PII> ival;multiset<int> q;void split(int x){ auto it=ival.lower_bound(PII(x+1,0)); if (it==ival.begin()) return; it--; int a=it->first,b=it->second; ival.erase(it); q.erase(q.find(dp[a][b])); if (a<x) { ival.insert(PII(a,x-1)); q.insert(dp[a][x-1]); } if (x<b) { ival.insert(PII(x+1,b)); q.insert(dp[x+1][b]); }}int main(){ int T,n; scanf("%d",&T); for (int t=1;t<=T;t++) { scanf("%d",&n); memset(vis,0,sizeof(vis)); for (int i=1;i<MAX;i++) { p[i].clear(); } for (int i=1;i<=n;i++) { scanf("%d",&a[i]); p[a[i]].push_back(i); } for (int i=1;i<=n;i++) { bool f=true; for (int j=i;j<=n;j++) { if (vis[a[j]]==i) { f=false; } vis[a[j]]=i; isok[i][j]=f; } } for (int len=1;len<=n;len++) { for (int i=1;i+len-1<=n;i++) { int j=i+len-1; if (isok[i][j]) { dp[i][j]=j-i+1; } else { dp[i][j]=max(dp[i+1][j],dp[i][j-1]); } } } int ans=-1; memset(vis,0,sizeof(vis)); for (int i=1;i<=n;i++) { ival.clear();q.clear(); ival.insert(PII(1,n)); q.insert(dp[1][n]); for (int j=i;j<=n;j++) { if (vis[a[j]]==i) { break; } vis[a[j]]=i; for (auto x:p[a[j]]) { split(x); } int cur=j-i+1; if (!q.empty()) { cur+=*q.rbegin(); } ans=max(cur,ans); } } printf("Case #%d: %d\n",t,ans); } return 0;}
这个方法更优的地方在于它并没有一定要保存合法的区间(如
复杂度同样为
D. Ice Cream Tower
这题应该说比较容易。读懂题目应该可以想到答案具有单调性,所以可以二分答案。记二分当前结果为
不想动态申请内存的可以像这样使用滚动数组。
#include <bits/stdc++.h>using namespace std;typedef long long ll;typedef pair<int,int> PII;const int N=3e5+5;int T,n,k;ll b[N],to[N][2];bool ok(int m){ int p=1; int pre=0,now=1; for (int j=1;j<=m;j++) { to[j][pre]=b[p++]; } for (int i=1;i<k;i++) { for (int j=1;j<=m;j++) { while (p<=n&&b[p]<to[j][pre]*2) p++; if (p>n) return false; to[j][now]=b[p++]; } swap(pre,now); } return true;}int bs(int l,int r){ int res=0; while (l<=r) { int m=(l+r)>>1; if (ok(m)) { res=m;l=m+1; } else { r=m-1; } } return res;}int main(){ scanf("%d",&T); for (int t=1;t<=T;t++) { scanf("%d%d",&n,&k); for (int i=1;i<=n;i++) { scanf("%lld",&b[i]); } sort(b+1,b+1+n); int ans=bs(1,n/k); printf("Case #%d: %d\n",t,ans); } return 0;}
E. Bet
。。。这题本身是容易的。。。但是。。。
记对第
该式对
于是我又是问q巨要的代码。。。然后我感觉Java很厉害。。。
import java.math.BigInteger;import java.util.Scanner;public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int T = sc.nextInt(); BigInteger[] up = new BigInteger[100]; BigInteger[] down = new BigInteger[100]; for (int t = 1; t <= T; t++) { int n = sc.nextInt(); sc.nextLine(); for (int i = 0; i < n; i++) { String str = sc.nextLine(); String[] da = str.split(":"); double x = Double.parseDouble(da[0]) * 1000; double y = Double.parseDouble(da[1]) * 1000; BigInteger a = BigInteger.valueOf((long) x); BigInteger b = BigInteger.valueOf((long) y); BigInteger g = a.gcd(b); up[i] = a.divide(g); down[i] = a.add(b).divide(g); } for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) { if (up[i].multiply(down[j]).compareTo(down[i].multiply(up[j])) > 0) { BigInteger tmp = up[i]; up[i] = up[j]; up[j] = tmp; tmp = down[i]; down[i] = down[j]; down[j] = tmp; } } } BigInteger su = BigInteger.ZERO; BigInteger sd = BigInteger.ONE; int ans = 0; for (int i = 0; i < n; i++) { BigInteger nu = su.multiply(down[i]).add(sd.multiply(up[i])); BigInteger nd = sd.multiply(down[i]); BigInteger g = nu.gcd(nd); su = nu.divide(g); sd = nd.divide(g); if (su.compareTo(sd) < 0) { ans += 1; } else { break; } } System.out.println("Case #" + t + ": " + ans); } }}
F. Mr. Panda and Fantastic Beasts
比赛的时候还什么都不会。。。现在知道可以用后缀数组或者后缀自动机做,先只学后缀数组吧。。。
这么多串第一步就是加特殊字符全连在一起,用倍增法实现SA。记第一个串为
The solution above is based on forever97’s.
至于
#include <bits/stdc++.h>using namespace std;typedef long long ll;const int MAXN=300030;char s[MAXN];int str[MAXN];int sa[MAXN];int t1[MAXN],t2[MAXN],c[MAXN];int rk[MAXN],height[MAXN];bool cmp(int *r,int a,int b,int l){ return r[a] == r[b] && r[a+l] == r[b+l];}void da(int str[],int sa[],int rank[],int height[],int n,int m){ n++; int i, j, p, *x = t1, *y = t2; for(i = 0; i < m; i++)c[i] = 0; for(i = 0; i < n; i++)c[x[i] = str[i]]++; for(i = 1; i < m; i++)c[i] += c[i-1]; for(i = n-1; i >= 0; i--)sa[--c[x[i]]] = i; for(j = 1; j <= n; j <<= 1) { p = 0; for(i = n-j; i < n; i++)y[p++] = i; for(i = 0; i < n; i++)if(sa[i] >= j)y[p++] = sa[i] - j; for(i = 0; i < m; i++)c[i] = 0; for(i = 0; i < n; i++)c[x[y[i]]]++; for(i = 1; i < m; i++)c[i] += c[i-1]; for(i = n-1; i >= 0; i--)sa[--c[x[y[i]]]] = y[i]; swap(x,y); p = 1; x[sa[0]] = 0; for(i = 1; i < n; i++) x[sa[i]] = cmp(y,sa[i-1],sa[i],j)?p-1:p++; if(p >= n)break; m = p; } int k = 0; n--; for(i = 0; i <= n; i++)rank[sa[i]] = i; for(i = 0; i < n; i++) { if(k)k--; j = sa[rank[i]-1]; while(str[i+k] == str[j+k])k++; height[rank[i]] = k; }}void solve(int lim,int n){ int ans=n+1,pos=-1; for (int i=1;i<=n;i++) { while (i<=n&&sa[i]>=lim) i++; if (i>n) break; int cur1=height[i]; for (int p=i-1;p&&sa[p]<lim;p--) { cur1=min(cur1,height[p]); } int cur2=height[i+1]; for (int q=i+1;q<=n&&sa[q]<lim;q++) { cur2=min(cur2,height[q+1]); } int cur=max(cur1,cur2); if (cur<lim-sa[i]) { if (cur+1<ans) { ans=cur+1; pos=sa[i]; } } } if (pos==-1) { puts("Impossible"); } else { for (int i=0;i<ans;i++) { putchar(str[pos+i]); } puts(""); }}int main(){ int T,n; scanf("%d",&T); for (int t=1;t<=T;t++) { scanf("%d",&n); int up=140,len=0,firstl; for (int i=1;i<=n;i++) { scanf("%s",s); int nl=strlen(s); if (i==1) firstl=nl; for (int j=0;j<nl;j++) { str[len++]=s[j]; } str[len++]=up+i; } str[--len]=0; da(str,sa,rk,height,len,up+n); printf("Case #%d: ",t); solve(firstl,len); } return 0;}
warning: 不赞成使用 height[0]/height[n+1] 。
H. Great Cells
拆开来用贡献做实在是太神奇了。。。dp+容斥不太适合我的能力。。。
第一项相当于每个格子当一次great cell就计数一次,第二项相当于所有填法的总和。
第一项转化为每一个格子的贡献(当great cell的次数)。一个格子为great cell当且仅当这个格子填
于是这道题成为了本场代码第二短的。。。
#include <bits/stdc++.h>using namespace std;typedef long long ll;const int MO=1e9+7;ll fpow(ll x,int n){ ll res=1; while (n) { if (n&1) { res=res*x%MO; } n>>=1; x=x*x%MO; } return res;}int main(){ int T; scanf("%d",&T); for (int t=1;t<=T;t++) { ll n,m,k,ans=0; scanf("%I64d%I64d%I64d",&n,&m,&k); for (int i=1;i<k;i++) { ans=(ans+fpow(i,n+m-2))%MO; } ans=ans*fpow(k,(n-1)*(m-1))%MO; ans=ans*n%MO*m%MO; ans=(ans+fpow(k,n*m))%MO; if (n==1&&m==1) { ans=(ans+1)%MO; } printf("Case #%d: %I64d\n",t,ans); } return 0;}
L. World Cup
总共六场比赛,每场三种结果,暴力。
#include <bits/stdc++.h>using namespace std;typedef long long ll;typedef pair<int,int> PII;int match[][2]={{1,2},{1,3},{1,4},{2,3},{2,4},{3,4}};struct Result { int a,b,c,d; Result() { } Result(int w,int x,int y,int z) { a=w;b=x;c=y;d=z; }} r[1000];int top,s[5];void dfs(int dep){ if (dep>=6) { r[top++]=Result(s[1],s[2],s[3],s[4]); return; } s[match[dep][0]]+=3; dfs(dep+1); s[match[dep][0]]-=3; s[match[dep][1]]+=3; dfs(dep+1); s[match[dep][1]]-=3; s[match[dep][0]]+=1; s[match[dep][1]]+=1; dfs(dep+1); s[match[dep][0]]-=1; s[match[dep][1]]-=1;}int count(int a,int b,int c,int d){ int res=0; for (int i=0;i<top;i++) { if (r[i].a==a&&r[i].b==b&&r[i].c==c&&r[i].d==d) res++; } return res;}int main(){ top=0; memset(s,0,sizeof(s)); dfs(0); int T; scanf("%d",&T); for (int t=1;t<=T;t++) { int a,b,c,d; scanf("%d%d%d%d",&a,&b,&c,&d); printf("Case #%d: ",t); int cnt=count(a,b,c,d); if (cnt==0) puts("Wrong Scoreboard"); else if (cnt==1) puts("Yes"); else puts("No"); } return 0;}
Coda
因为总是搜不到题解,于是就劳烦了好多人。。。但是大佬们都很友好,作为一个鶸我真的非常感动,值得学习!
特别鸣谢 quailty@codeforces, forever97@codeforces 我q人见人爱!
- 2016 China-Final 解题报告
- (转载)2016 China-Final 解题报告
- 2016 icpc china final
- zoj1444 Final Standings解题报告
- 2016 ICPC China Final 总结
- ZOJ 3721 Final Exam Arrangement 解题报告
- 2016icpc China-final D题
- 2016 China-Final A. Number Theory Problem
- 2016 China-Final Ice Cream Tower(二分)
- 2016China Final 二分 UVALive7900(D)
- 2016-2017 ACM-ICPC CHINA-Final
- BUAA-SCSE 暑期算法提高班 Final Contest 解题报告
- ZOJ 3721 Final Exam Arrangement 解题报告 (贪心)
- 2016NHOI解题报告
- 解题报告:CROC 2016
- Problem A. Number Theory Problem(2016China-Final)【找规律】
- Problem L. World Cup(2016China-Final)【暴力】
- Problem H. Great Cells(2016 China-Final)【数学计数+智力题】
- 关于云计算、2017年的5大颠覆性因素!
- 批量修改文件名(find & rename & sed)
- Verilog 数字电路设计之带hazard的五级流水线CPU
- 通过maven将springboot项目发布为jar包
- Android:学习AIDL,这一篇文章就够了(上)
- 2016 China-Final 解题报告
- 在c++中,有哪4个与类型转换相关的关键字,这些关键字各有什么特点,应该在什么场合下使用?
- vue.js学习(二)
- C/C++中extern关键字详解
- 前缀、中缀、后缀表达式
- ss5客户端设置
- 第四十章 SpringBoot AOP
- Canvas 实现时钟
- Java并发编程的艺术(十)——线程池(1)