前记
眼看他起高楼;眼看他宴宾客;眼看他楼坍了。
比赛历程
开考前一分钟还在慌里慌张地订正上午考试题目。
“诶这个数位dp哪里见了鬼了???”瞥了眼时间,无奈而迅速地关去所有其他窗口,临时打了一个缺省源。
A. Phone Numbers
那么就是模拟。
1 #include<bits/stdc++.h> 2 3 int n,x; 4 char s[103]; 5 6 int read() 7 { 8 char ch = getchar(); 9 int num = 0; 10 bool fl = 0; 11 for (; !isdigit(ch); ch=getchar()) 12 if (ch=='-') fl = 1; 13 for (; isdigit(ch); ch=getchar()) 14 num = (num<<1)+(num<<3)+ch-48; 15 if (fl) num = -num; 16 return num; 17 } 18 int main() 19 { 20 n = read(); 21 scanf("%s",s); 22 for (int i=0; i<n; i++) 23 if (s[i]=='8') x++; 24 printf("%d ",std::min(x, n/11)); 25 return 0; 26 }
B. Maximum Sum of Digits
结论题。构造尽可能多的999……
1 #include<bits/stdc++.h> 2 typedef long long ll; 3 4 ll n,num; 5 6 long long read() 7 { 8 char ch = getchar(); 9 long long num = 0; 10 bool fl = 0; 11 for (; !isdigit(ch); ch=getchar()) 12 if (ch=='-') fl = 1; 13 for (; isdigit(ch); ch=getchar()) 14 num = (num<<1)+(num<<3)+ch-48; 15 if (fl) num = -num; 16 return num; 17 } 18 ll calc(ll x) 19 { 20 ll ret=0; 21 for (; x; x/=10) ret += x%10; 22 return ret; 23 } 24 int main() 25 { 26 n = read(), num = 0; 27 while (num < n) num = num*10+9; 28 num /= 10; 29 printf("%lld ",calc(num)+calc(n-num)); 30 return 0; 31 }
C. Maximum Subrectangle
有点意思的题:找一个面积最大,权值和小于lim的矩阵。但是这个矩阵有个特殊性质:它不是没有规律地给定,而是由两个数列相乘构造而来。n<=2000.
做法一:
先枚举一个维,将这个维所有的段长和元素和都存下来,然后sort一下。另一维枚举,二分寻找最大能够匹配的段。
时间复杂度$O(n^2log_2n)$
做法二:
然而上面一个做法的浪费在于存下所有的段。注意到这个决策是单调的,对于长度相同的段,只有元素和最小的是有用的。那么对于两个维,都记录这个最小值。最后分别枚举两维的长度时直接匹配。
时间复杂度$O(n^2)$
1 #include<bits/stdc++.h> 2 const int maxn = 2035; 3 4 struct node 5 { 6 int a,b; 7 bool operator < (node x) const 8 { 9 if (a < x.a) return a < x.a; 10 return b < x.b; 11 } 12 }sv[6000035]; 13 int a[maxn],b[maxn],n,m,lim; 14 int sa[maxn],sb[maxn]; 15 int mna[maxn],mnb[maxn]; 16 int cnt,ans; 17 18 int read() 19 { 20 char ch = getchar(); 21 int num = 0; 22 bool fl = 0; 23 for (; !isdigit(ch); ch=getchar()) 24 if (ch=='-') fl = 1; 25 for (; isdigit(ch); ch=getchar()) 26 num = (num<<1)+(num<<3)+ch-48; 27 if (fl) num = -num; 28 return num; 29 } 30 int main() 31 { 32 memset(mna, 0x3f3f3f3f, sizeof mna); 33 memset(mnb, 0x3f3f3f3f, sizeof mnb); 34 n = read(), m = read(); 35 for (int i=1; i<=n; i++) a[i] = read(), sa[i] = sa[i-1]+a[i]; 36 for (int i=1; i<=m; i++) b[i] = read(), sb[i] = sb[i-1]+b[i]; 37 lim = read(); 38 for (int i=1; i<=n; i++) 39 for (int j=i; j<=n; j++) 40 mna[j-i+1] = std::min(mna[j-i+1], sa[j]-sa[i-1]); 41 for (int i=1; i<=m; i++) 42 for (int j=i; j<=m; j++) 43 mnb[j-i+1] = std::min(mnb[j-i+1], sb[j]-sb[i-1]); 44 for (int i=1; i<=n; i++) 45 for (int j=1; j<=m; j++) 46 if (1ll*mna[i]*mnb[j] <= 1ll*lim) 47 ans = std::max(ans, i*j); 48 printf("%d ",ans); 49 return 0; 50 }
D. Social Circles
开场时候原本就打算手速D的,又恰巧总榜上D被秒掉了。于是弃了BC就去看D……
想了好久也没有什么靠谱做法,这时t老师6分钟就写完了D,瞬间心态崩坏。
想啊想啊,是个贪心?图论?然而一点没往结论题方向想。
没办法只能转回头去做C。脑子里一团浆糊,什么也想不进去。
最后是等到XCW在1:09大力猜结论过了pretest机房才大队人马过D。
大致题意:有n个人,每个人要求自己左边有li张空椅子;右边有ri张空椅子。可以把不同的人任意分组。问最小需要的总椅子数量。
结论是:这些人的左右手要求是可以互换的。那么就是排序之后取max。
好像现在官方题解还没出来?那么这个结论我也没法证明……
1 #include<bits/stdc++.h> 2 const int maxn = 100035; 3 4 int n,a[maxn],b[maxn]; 5 long long ans; 6 7 int main() 8 { 9 scanf("%d",&n); 10 for (int i=1; i<=n; i++) scanf("%d",&a[i]); 11 for (int i=1; i<=n; i++) scanf("%d",&b[i]); 12 std::sort(a+1, a+n+1); 13 std::sort(b+1, b+n+1); 14 for (int i=1; i<=n; i++) ans += std::max(a[i], b[i]); 15 printf("%lld ",ans); 16 return 0; 17 }
E. Sergey and Subway
花CD的时间太久了……E题题意直接去问同学了。
然而刚开始一段时间把题意理解错了。
大致题意:现在有一颗树,边权均为1。每次操作将原树上距离为2的点,在新树上连接一条边权为1的边。进行操作直到不能再操作为止。询问新树两两点对距离和。
首先是结论:原树上长度为$d$的路径,在新树上长度变为$frac{d+1}{2}(向下取整)$。
这个比较容易理解:对于长度为2的路径,长度变为1;长度为1的路径,长度不变;然后任意一条路径都可以视作由2、1的路径拼接而成。
第一感觉是点分?但是一看时间不大对了直接去求助t老师了。
t老师:不用点分……一开始我写了一个很复杂的上下dp。这个题超傻逼的,只要枚举边计算贡献。然后计奇数路径条数。深度奇偶性不同的就是奇数路径。
哇好有道理的样子哦。想了想就开始码(然而中间还码错了点小细节耽搁一会),然后就愉快地过掉了。(但是毕竟还是手速太慢,E题最后只有1008的分)
1 #include<bits/stdc++.h> 2 const int maxn = 200035; 3 4 long long ans; 5 int n,tot[maxn],dep[maxn],sum[3]; 6 int edges[maxn<<1],nxt[maxn<<1],head[maxn],edgeTot; 7 8 int read() 9 { 10 char ch = getchar(); 11 int num = 0; 12 bool fl = 0; 13 for (; !isdigit(ch); ch=getchar()) 14 if (ch=='-') fl = 1; 15 for (; isdigit(ch); ch=getchar()) 16 num = (num<<1)+(num<<3)+ch-48; 17 if (fl) num = -num; 18 return num; 19 } 20 void addedge(int u, int v) 21 { 22 edges[++edgeTot] = v, nxt[edgeTot] = head[u], head[u] = edgeTot; 23 edges[++edgeTot] = u, nxt[edgeTot] = head[v], head[v] = edgeTot; 24 } 25 void dfs(int x, int fa) 26 { 27 tot[x] = 1, dep[x] = dep[fa]+1, sum[dep[x]&1]++; 28 for (int i=head[x]; i!=-1; i=nxt[i]) 29 { 30 int v = edges[i]; 31 if (v!=fa){ 32 dfs(v, x); 33 tot[x] += tot[v]; 34 long long t = 1ll*tot[v]*(n-tot[v]); 35 ans += t; 36 } 37 } 38 } 39 int main() 40 { 41 memset(head, -1, sizeof head); 42 n = read(); 43 for (int i=1; i<n; i++) addedge(read(), read()); 44 dfs(1, 1); 45 ans += 1ll*sum[0]*sum[1]; 46 printf("%lld ",ans/2); 47 return 0; 48 }
xor则是发现了点分FFT的写法,恰巧以前度教出过一道类似的题,于是机房大队人马搬来自己代码争先恐后地过了pretest。
【后话:除了我和xor其他人都FST了;反正WA、RE、TLE全齐了】
后记
哎,暑假一共就打了两场,打得还非常差。现在也不过是一直在expert徘徊。
反观同级甚至初中的大佬,已经不是Grandmaster就是Master最差Candiate Master了。
考试时候依然起伏不定,思维发挥也没有达到所期望的那种地步。
即便是往年今日,zx2003也早就上紫了啊!
“How BAD do you want it?”