终于打了一场CF,不知道为什么我会去打00:05的CF比赛……

不管怎么样,这次打的很好!拿到了Div. 2选手中的第一名,成功上紫!

以后还要再接再厉!


【A】Check the string

题意:

一个合法的字符串可以这样生成:

初始是一个空串,然后小 A 同学往这个串中加入若干(大于零)个字符\(\texttt{a}\),然后小 B 同学往这个串的末尾加入若干(大于零)个字符\(\texttt{b}\),最后小 C 同学往这个串的末尾加入一些字符\(\texttt{c}\),但要满足\(\texttt{c}\)的个数等于\(\texttt{a}\)的个数或\(\texttt{b}\)的个数。

问一个字符串是否是合法的。

题解:

模拟,注意细节。

  1. #include<bits/stdc++.h>
  2.  
  3. char str[10000];
  4. int i,n,A,B,C;
  5.  
  6. int main(){
  7. scanf("%s",str); n=strlen(str);
  8. if(str[0]!='a') {puts("NO"); return 0;}
  9. for(i=0;i<n;++i) if(str[i]=='a') ; else break;
  10. A=i;
  11. if(i==n||str[i]!='b') {puts("NO"); return 0;}
  12. for(;i<n;++i) if(str[i]=='b') ; else break;
  13. if(i==n||str[i]!='c') {puts("NO"); return 0;}
  14. B=i-A;
  15. for(;i<n;++i) if(str[i]=='c') ; else break;
  16. if(i!=n) {puts("NO"); return 0;}
  17. C=n-B-A;
  18. if(C!=A&&C!=B) {puts("NO"); return 0;}
  19. puts("YES");
  20. return 0;
  21. }

【B】Minimize the error

题意:

有两个长度都为\(n\)的数组\(A\)和\(B\),定义误差\(E=\sum_{i=1}^{n}(A_i-B_i)^2\)。

你需要对数组\(A\)执行恰好\(k_1\)次操作,对数组\(B\)执行恰好\(k_2\)次操作。一次操作即让数组中的一个数加一,或者减一。

问执行完操作后的最小误差\(E\)。

题解:

数组的每一位都是独立的。对于某一位\(A_i,B_i\),对这一位执行操作可以让\((A_i-B_i)^2=|A_i-B_i|^2\)变大,或者变小。

显然变大是不合算的,所以计算出\(C_i=|A_i-B_i|\),不论是对\(A\)还是对\(B\)的操作都是一样的,可以让\(C_i\)加一或者减一,但是不能减到负数。

而\(C_i\)越大,对它减一的收益就越大,所以每次贪心选取最大的\(C_i\)减去一。我使用了优先队列来加快速度,尽管暴力可过。

  1. #include<bits/stdc++.h>
  2. #define F(i,a,b) for(int i=a;i<=(b);++i)
  3. #define ll long long
  4. using namespace std;
  5.  
  6. int n,A,B;
  7. int a[100001],b[100001];
  8. priority_queue<int> pq;
  9. ll Ans=0;
  10.  
  11. int main(){
  12. scanf("%d%d%d",&n,&A,&B); A+=B;
  13. F(i,1,n) scanf("%d",a+i);
  14. F(i,1,n) scanf("%d",b+i);
  15. F(i,1,n) a[i]=abs(a[i]-b[i]), pq.push(a[i]);
  16. F(i,1,A){
  17. int x=pq.top(); pq.pop();
  18. if(x>0) pq.push(x-1);
  19. else pq.push(1);
  20. }
  21. int x;
  22. F(i,1,n) x=pq.top(), Ans+=(ll)x*x, pq.pop();
  23. printf("%lld",Ans);
  24. return 0;
  25. }

【C】Subsequence Counting

题意:

对于一个数组,将这个数组的所有非空子序列写下,然后删掉满足:最大值与最小值的差大于等于\(d\)的子序列。

最后剩下了\(X\)个子序列。

请你给出原序列的一种合法排列。

题解:

考虑这样构造:

\(\overset{k_1}{\overbrace{x,\cdots,x}},\overset{k_2}{\overbrace{x+d,\cdots,x+d}},\overset{k_3}{\overbrace{x+2d,\cdots,x+2d}},\cdots\)。

这样的目的是让任意包含两个不同的数的子序列会被删掉,留下的只有包含相同数的。

这样最终剩下的子序列有多少个呢?通过一些简单的计算,我们得到答案:

\(\sum 2^{k_i}-1\)。

得到了这个,发现两组个数分别为\(k_i\)和\(1\)的数,会对答案产生\(2^{k_i}\)的贡献。

那么把\(X\)二进制拆分一下即可。

  1. #include<bits/stdc++.h>
  2. #define F(i,a,b) for(int i=a;i<=(b);++i)
  3. #define ll long long
  4.  
  5. int X,d,cnt;
  6. ll now=1;
  7. ll b[100001];
  8.  
  9. int main(){
  10. scanf("%d%d",&X,&d);
  11. if(X&1) {b[++cnt]=now; now+=d;}
  12. int x=1; X>>=1;
  13. while(X){
  14. if(X&1){
  15. for(int i=1;i<=x;++i) b[++cnt]=now;
  16. now+=d;
  17. b[++cnt]=now;
  18. now+=d;
  19. }
  20. X>>=1; ++x;
  21. }
  22. printf("%d\n",cnt);
  23. F(i,1,cnt) printf("%lld ",b[i]);
  24. return 0;
  25. }

【D】Full Binary Tree Queries

题意:

给你一个无限层的满二叉树(无限层也不考虑是完全还是满了2333)。

这个满二叉树的节点上有值,而且一个节点的左儿子的值是这个节点的值乘以2,右儿子的值是这个节点的值乘2加1。

你有三个操作:

①把值为X的节点所在层的所有节点的值往右循环移动K位。

②把值为X的节点所在层的所有节点往右循环移动K位,子树也一起移动。

③问值为X的节点走到根的路径上的值的序列。

请执行这些操作,并回答结果。

题解:

发现初始一个节点的值可以很轻松算出来,其实就是线段树上的节点的编号,很有规律。

因为\(X\)在long long范围,所以深度大于62的都是假的节点。

考虑暴力维护每一层循环移动的位数。再做做数学加加减减就完事了。

  1. #include<bits/stdc++.h>
  2. #define F(i,a,b) for(int i=a;i<=(b);++i)
  3. #define dF(i,a,b) for(int i=a;i>=(b);--i)
  4. #define ll long long
  5.  
  6. int n;
  7. ll lev[64];
  8.  
  9. inline int hibit(ll x){
  10. int ans=-1;
  11. while(x) x>>=1, ++ans;
  12. return ans;
  13. }
  14. inline void shift(int lv,ll k){lev[lv]+=k&((1ll<<lv)-1);lev[lv]&=((1ll<<lv)-1);}
  15.  
  16. int main(){
  17. scanf("%d",&n);
  18. F(i,1,n){
  19. int t; ll x,k;
  20. scanf("%d%lld",&t,&x);
  21. if(t==1){
  22. scanf("%lld",&k);
  23. shift(hibit(x),k);
  24. }
  25. if(t==2){
  26. scanf("%lld",&k);
  27. F(j,hibit(x),61)
  28. shift(j,k<<(j-hibit(x)));
  29. }
  30. if(t==3){
  31. int lv=hibit(x);
  32. ll y=(x-(1ll<<lv)+lev[lv])&((1ll<<lv)-1);
  33. dF(j,lv,0) printf("%lld ",((y-lev[j])&((1ll<<j)-1))+(1ll<<j)), y>>=1; puts("");
  34. }
  35. }
  36. return 0;
  37. }

【E】Alternating Tree

题意:

对于一棵树,假设有一条简单路径\(u_1 \rightarrow u_2 \rightarrow u_3 \rightarrow \dots u_{m-1} \rightarrow u_{m}\)。

定义它的交替函数:\(A(u_{1},u_{m}) = \sum\limits_{i=1}^{m} (-1)^{i+1} \cdot V_{u_{i}}\)。

一条路径也可以有\(0\)条边,即\(u_1=u_m\)。

请计算所有不同路径的交替函数值的总和。答案对\(10^9+7\)取模。

题解:

考虑对于每一个点计算自己的贡献。

为了好处理,把树变成以1为根的有根树。

再考虑一个点的贡献:显然只有经过这个点的路径才会有贡献,即起点在这个点的一个子树(父亲连接的也算作一个子树),终点在其他子树的路径。

而对于一个路径,显然该点在奇数位贡献为正数,否则是负数。假设当前点为\(u\)。

对于起点在某一个大小为\(siz\)的子树中的\(v\)点,这个点在\(u\)的贡献就是\((-1)^{dis_{v,u}}\times (n-siz)\)。

\(n-siz\)即为终点可以在的位置的个数,只要不在同一个子树就可以。

发现只要\(v\)在同一个子树,最后乘的\(n-siz\)都是相同的。考虑把前面的也合并起来。

那么以\(u\)为根建树,\(u\)直接相连的每一个子树\(T\)都定义一个函数\(f(T)=\sum_{v\in T}(-1)^{dep_v}\)。

当\(v\)为\(T\)的根时,\(dep_v=0\),之后每一层\(dep\)就多一。

这个函数有什么意义呢?发现\(f(T)\)正好就是刚刚的\((-1)^{dis_{v,u}}\)的总和的相反数。

那就是说子树\(T\)对\(u\)的贡献次数是\(-f(T)\times (n-siz_T)=-f(T)\cdot n+f(T)\cdot siz_T\)。

但是还漏了一种起点就是\(u\)本身的情况,那样会多贡献正好\(n\)次。

那就是说,总贡献是\((1-\sum f(T))\cdot n+\sum f(T)\cdot siz_T\)。

那\(siz_T\)通过DFS比较好算,考虑一下\(f(T)\)如何求出。

假如已经以\(u\)为根了,那么\(f(T)\)可以递归计算:\(f(T)=1-\sum f(G)\),其中\(G\)是与\(T\)直接相连的子树。

这和刚刚的公式是一样的结构,也就是说总贡献为\(f(T_u)\cdot n+\sum f(T)\cdot siz_T\),\(T_u\)即以\(u\)为根的整棵树。

但是这样还不够,因为要通过DFS计算答案,就必须指定一个点为根,比如\(1\)号点。

那么这时还能统计出每个\(u\)的每个\(f(T)\)吗?

考虑以\(1\)为根时的每个\(f(T)\),那么以\(u\)为根时,\(f(T_u)\)就等于\(f(1)\)或者\(-f(1)\)。当\(u\)的深度是偶数(1的深度为0)时,就是\(f(1)\),否则取相反数。

而对于\(u\)的\(f(T)\)呢?对于\(u\)的儿子的\(f(T)\),值不变,但是\(u\)还有一个指向父亲的\(T\),其实这个\(f(T)\)就等于\(f(T_u)\)【这个指的是以1为根的】减去\(f(T_u)\)【这个指的是以u为根的,即上面算出来的\(f(1)\)或相反数】。

那么一次DFS求出siz、dep和f值,第二次DFS直接求答案即可。

  1. #include<bits/stdc++.h>
  2. #define F(i,a,b) for(int i=a;i<=(b);++i)
  3. #define eF(i,u) for(int i=h[u];i;i=nxt[i])
  4. #define ll long long
  5.  
  6. int Mod=1000000007;
  7. int n,q;
  8. int val[200001];
  9.  
  10. int h[200001],nxt[400001],to[400001],tot;
  11. inline void ins(int x,int y){nxt[++tot]=h[x];to[tot]=y;h[x]=tot;}
  12.  
  13. int f[200001],siz[200001],dep[200001];
  14.  
  15. ll Ans;
  16.  
  17. void DFS(int u,int fa){
  18. f[u]=1; dep[u]=dep[fa]+1; siz[u]=1;
  19. eF(i,u) if(to[i]!=fa) DFS(to[i],u), f[u]-=f[to[i]], siz[u]+=siz[to[i]];
  20. }
  21.  
  22. void D2(int u,int fa){
  23. eF(i,u) if(to[i]!=fa){
  24. D2(to[i],u);
  25. Ans=((Ans+(ll)f[to[i]]*siz[to[i]]%Mod*val[u]%Mod)%Mod+Mod)%Mod;
  26. }
  27. if(fa!=0) Ans=((Ans+(ll)(((dep[u]&1)?-f[1]:f[1])+f[u])*(n-siz[u])%Mod*val[u]%Mod)%Mod+Mod)%Mod;
  28. }
  29.  
  30. int main(){
  31. int x,y;
  32. scanf("%d",&n);
  33. F(i,1,n) scanf("%d",val+i);
  34. F(i,2,n) scanf("%d%d",&x,&y), ins(x,y), ins(y,x);
  35. DFS(1,0);
  36. F(i,1,n) if(dep[i]&1) Ans+=(ll)f[1]*val[i]; else Ans-=(ll)f[1]*val[i];
  37. Ans=(Ans%Mod+Mod)%Mod; Ans=Ans*n%Mod;
  38. D2(1,0);
  39. printf("%lld\n",Ans);
  40. return 0;
  41. }

【F】Pathwalks

题意:

给定一个有向图,边有边权。

问最长的路径,满足条件:边权逐个严格增加,并且边的顺序是读入时的顺序。

只要回答长度即可。

题解:

用\(dp[i][j]\)表示走到节点\(i\),并且最后的边权为\(j\)时的最长路径长度。

有转移:\(dp[i][j]=max(dp[k][l])+1,(l\leq k\to i)\)。

但是还要边的顺序是读入时的顺序。

那可以边读入边转移:读入\(u\to v=w\)时,可以转移\(dp[v][w]=max(dp[u][l])+1,(l\leq w)\)。

但是dp[i][j]存储的状态太多了,而且处理最大值也很吃力。

但是发现能转移的状态很少,而最大值是一个区间。

于是用动态开点的线段树解决这个问题。不需要离散化。

【也可以树状数组,因为求得是前缀】

  1. #include<bits/stdc++.h>
  2. #define F(i,a,b) for(int i=a;i<=(b);++i)
  3. using namespace std;
  4.  
  5. int n,m,Ans;
  6. int a[100001],b[100001];
  7. int u[100001],v[100001],w[100001];
  8. int f[100001];
  9.  
  10. int dat[8000001],ls[8000001],rs[8000001],cnt;
  11.  
  12. int Maxi(int rt,int l,int r,int a,int b){
  13. if(a>b) return 0;
  14. if(r<a||b<l) return 0;
  15. if(a<=l&&r<=b) return dat[rt];
  16. if(!ls[rt]) ls[rt]=++cnt;
  17. if(!rs[rt]) rs[rt]=++cnt;
  18. int mid=l+r>>1;
  19. return max(Maxi(ls[rt],l,mid,a,b),Maxi(rs[rt],mid+1,r,a,b));
  20. }
  21.  
  22. void Ins(int rt,int l,int r,int p,int x){
  23. if(l==r) {dat[rt]=x; return;}
  24. if(!ls[rt]) ls[rt]=++cnt;
  25. if(!rs[rt]) rs[rt]=++cnt;
  26. int mid=l+r>>1;
  27. if(p<=mid) Ins(ls[rt],l,mid,p,x);
  28. else Ins(rs[rt],mid+1,r,p,x);
  29. dat[rt]=max(dat[ls[rt]],dat[rs[rt]]);
  30. }
  31.  
  32. int main(){
  33. scanf("%d%d",&n,&m); cnt=n;
  34. F(i,1,m) scanf("%d%d%d",u+i,v+i,w+i), ++w[i];
  35. F(i,1,m){
  36. f[i]=Maxi(u[i],1,100001,1,w[i]-1)+1;
  37. Ins(v[i],1,100001,w[i],f[i]);
  38. }
  39. F(i,1,m) Ans=max(Ans,f[i]);
  40. printf("%d",Ans);
  41. return 0;
  42. }

【codeforces】【比赛题解】#960 CF Round #474 (Div. 1 + Div. 2, combined)的更多相关文章

  1. 【codeforces】【比赛题解】#868 CF Round #438 (Div.1+Div.2)

    这次是Div.1+Div.2,所以有7题. 因为时间较早,而且正好赶上训练,所以机房开黑做. 然而我们都只做了3题.:(. 链接. [A]声控解锁 题意: Arkady的宠物狗Mu-mu有一只手机.它 ...

  2. 竞赛题解 - CF Round #524 Div.2

    CF Round #524 Div.2 - 竞赛题解 不容易CF有一场下午的比赛,开心的和一个神犇一起报了名 被虐爆--前两题水过去,第三题卡了好久,第四题毫无头绪QwQ Codeforces 传送门 ...

  3. Educational Codeforces Round 65 (Rated for Div. 2)题解

    Educational Codeforces Round 65 (Rated for Div. 2)题解 题目链接 A. Telephone Number 水题,代码如下: Code #include ...

  4. Educational Codeforces Round 53 (Rated for Div. 2) (前五题题解)

    这场比赛没有打,后来补了一下,第五题数位dp好不容易才搞出来(我太菜啊). 比赛传送门:http://codeforces.com/contest/1073 A. Diverse Substring ...

  5. Educational Codeforces Round 63 (Rated for Div. 2) 题解

    Educational Codeforces Round 63 (Rated for Div. 2)题解 题目链接 A. Reverse a Substring 给出一个字符串,现在可以对这个字符串进 ...

  6. Educational Codeforces Round 48 (Rated for Div. 2) CD题解

    Educational Codeforces Round 48 (Rated for Div. 2) C. Vasya And The Mushrooms 题目链接:https://codeforce ...

  7. Educational Codeforces Round 60 (Rated for Div. 2) 题解

    Educational Codeforces Round 60 (Rated for Div. 2) 题目链接:https://codeforces.com/contest/1117 A. Best ...

  8. Educational Codeforces Round 59 (Rated for Div. 2) DE题解

    Educational Codeforces Round 59 (Rated for Div. 2) D. Compression 题目链接:https://codeforces.com/contes ...

  9. Educational Codeforces Round 58 (Rated for Div. 2) 题解

    Educational Codeforces Round 58 (Rated for Div. 2)  题目总链接:https://codeforces.com/contest/1101 A. Min ...

随机推荐

  1. 【Java并发编程】之六:Runnable和Thread实现多线程的区别

    Java中实现多线程有两种方法:继承Thread类.实现Runnable接口,在程序开发中只要是多线程,肯定永远以实现Runnable接口为主,因为实现Runnable接口相比继承Thread类有如下 ...

  2. Js数组和字符串常用方法

    字符串: 1.concat() – 将两个或多个字符的文本组合起来,返回一个新的字符串.  2.indexOf() – 返回字符串中一个子串第一处出现的索引.如果没有匹配项,返回 -1 .  3.ch ...

  3. HotSpot垃圾收集器GC的种类

      堆内存的结构:

  4. Powerful array CodeForces - 86D(莫队)

    给你n个数,m次询问,Ks为区间内s的数目,求区间[L,R]之间所有Ks*Ks*s的和.1<=n,m<=200000.1<=s<=10^6 #include <iostr ...

  5. Gson获取json串中的key-value

    1.依赖包 <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson& ...

  6. Alpha 冲刺 —— 十分之七

    队名 火箭少男100 组长博客 林燊大哥 作业博客 Alpha 冲鸭鸭鸭鸭鸭鸭鸭! 成员冲刺阶段情况 林燊(组长) 过去两天完成了哪些任务 协调各成员之间的工作 学习MSI.CUDA 试运行软件并调试 ...

  7. Linux下cp ~中关于“~”的疑问

    目的:将wi主文件夹下的.bashrc复制到/tmp,并更名为bashrc.对于书上的代码上加“~”存在疑问. cp ~/.bashrc /tmp/bashrc 对命令进行了以下尝试: 为什么不加“~ ...

  8. 构建工具-----Gradle(二)-----myeclipse 10和myeclipse2015安装gradle插件----其他版本的myeclipse类似

    我们需要给myeclipse安装gradle的插件.这样myeclipse就能识别到gradle项目了,直接加载进去即可. 我们先安装配置系统命令行的gradle,挺简单的,下载后配置环境变量即可,详 ...

  9. 解题:CF983B pyramid

    题面 题目都告诉我们是“金字塔”了,不妨分析分析$f$的性质 $f(a_1,a_2)=f(a_1$ $xor$ $a_2)=a1$ $xor$ $a_2$ $f(a_1,a_2,a_3)=f(a_1$ ...

  10. 【纪中集训2019.3.11】Cubelia

    题目: 描述 给出长度为\(n\)的数组\(a\)和\(q\)个询问\(l,r\). 求区间\([l,r]\)的所有子区间的前缀和的最大值之和: 范围: $n \le 2 \times 10^5 , ...