首页 > 其他分享 >Educational Codeforces Round 145 (Rated for Div. 2)

Educational Codeforces Round 145 (Rated for Div. 2)

时间:2023-04-29 17:12:07浏览次数:59  
标签:Educational Rated const int Codeforces CODE include RI define

Preface

补题

A~D都能秒出,E没看出性质被薄纱了,F感觉是个丁真题随便讨论下就过了

后面看了下F的标算是个倍增,感觉Tutorial对性质挖掘的还不够的说


A. Garland

SB题,设出现次数最多的颜色个数为\(cm\),若\(cm\le 2\)则答案为\(4\);若\(cm=3\)则答案为\(6\),若\(cm=4\)则无解

import java.util.*;
public class hl666 {
    public static void main(String args[]) {
        Scanner In=new Scanner(System.in);
        for (int t=In.nextInt();t>0;--t) {
            int x=In.nextInt();
            int[] c=new int[10];
            ++c[x%10]; ++c[x/10%10]; ++c[x/100%10]; ++c[x/1000];
            int cur=0;
            for (int i=0;i<10;++i) cur=Math.max(cur,c[i]);
            if (cur==4) {
                System.out.println("-1");
            } else if (cur==3) {
                System.out.println("6");
            } else {
                System.out.println("4");
            }
        }
    }
}

B. Points on Plane

SB题,画个图看下就发现答案一定是一层层间隔着取

然后稍微找下规律就会发现当答案为\(k\)时最多可以涵盖\((k+1)^2\)个点,因此直接开个根号就行了

import java.util.*;
public class hl666 {
    public static void main(String args[]) {
        Scanner In=new Scanner(System.in);
        for (int t=In.nextInt();t>0;--t) {
            long n=In.nextLong();
            long x=(long)Math.sqrt(n);
            if (x*x<n) ++x;
            System.out.println(x-1);
        }
    }
}

C. Sum on Subarrays

构造趣题,这题刚好在周四那场耻辱之战之前写的,然后就在吹嘘那构造题精通,结果后面原形毕露了捏

不过这题本身还是很trivial的,考虑先连着填充\(t\)个\(1\),然后剩下的位置都填\(-1000\),此时区间和为正数的区间个数显然就是\(\frac{t(t+1)}{2}\)

找出最大的且满足\(\frac{t(t+1)}{2}\le k\)的\(t\),然后考虑剩下的部分怎么处理,一个很naive的想法就是在后面继续找,然后如果不行有剩下的就在中间继续找

但这样一看就不是很优美而且有些情况根本构造不出来的说,我们考虑对原来的构造方法稍作修改

我们把前面\(t\)个位置中的某个位置改成\(1000\),然后把后面那一段\(-1000\)开头的那个改成\(-500\),因此此时的序列形如

\[1,1,\cdots,1000,1,1,\cdots,1,-500,-1000,-1000,\cdots \]

我们发现设\(1000\)的下标为\(r\),则此时多出的和为正数的区间个数恰好为\(r\)

而当\(t\)加一时\(\frac{t(t+1)}{2}\)的值恰好增加\(t+1\),而\(t\)本身可以额外加上\(t\)的贡献,因此一定可以涵盖所有情况

这样就很优美了的说

#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=35;
int t,n,k,a[N];
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	for (scanf("%d",&t);t;--t)
	{
		RI i,j; for (scanf("%d%d",&n,&k),i=1;i*(i+1)/2<=k;++i);
		for (--i,j=1;j<=i;++j) a[j]=1; a[k-i*(i+1)/2]=1000;
		for (a[i+1]=-500,j=i+2;j<=n;++j) a[j]=-1000;
		for (j=1;j<=n;++j) printf("%d%c",a[j]," \n"[j==n]);
	}
	return 0;
}

D. Binary String Sorting

这种题目刚开始都没什么好想的,上来就是一个DP,后面发现好像是个丁真结论题,不过无伤大雅

01串构成的LIS显然就是一段0再加上一段1,然后很经典的可以设计状态\(f_{i,p=0/1,q=0/1}\)表示以\(i\)结尾,结尾的两个字符为\(p,q\)且前\(i\)个字符构成的01串为LIS的最小代价

转移的话都很trivial,不过从\(p=1,q=1\)的状态接上一个\(0\)的情况就一定是删去\(0\),因为否则我们一定要用至少两次的交换操作,这显然不是最优的

代码非常的好写

#include<cstdio>
#include<iostream>
#include<cstring>
#define int long long
#define RI register int
#define CI const int&
using namespace std;
const int N=300005,S=1e12,INF=1e18;
int t,n,f[N][2][2],tmp; char s[N];
signed main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	for (scanf("%d",&t);t;--t)
	{
		RI i,p,q; for (scanf("%s",s+1),n=strlen(s+1),i=0;i<=n;++i)
		for (p=0;p<2;++p) for (q=0;q<2;++q) f[i][p][q]=INF;
		for (f[0][0][0]=0,i=0;i<n;++i) for (p=0;p<2;++p) for (q=0;q<2;++q)
		if (p<=q&&(tmp=f[i][p][q])!=INF)
		{
			f[i+1][p][q]=min(f[i+1][p][q],tmp+S+1);
			if (s[i+1]=='0')
			{
				if (p==0&&q==0) f[i+1][0][0]=min(f[i+1][0][0],tmp);
				if (p==0&&q==1) f[i+1][0][1]=min(f[i+1][0][1],tmp+S);
			} else f[i+1][q][1]=min(f[i+1][q][1],tmp);
		}
		int ans=INF; for (p=0;p<2;++p) for (q=0;q<2;++q)
		ans=min(ans,f[n][p][q]); printf("%lld\n",ans);
	}
	return 0;
}

后面一想发现由于这两个贡献都是\(10^{12}\)加上一个极小数的情形,因此只要在最小化总操作次数的情况下尽量多的用交换操作即可

可以直接枚举LIS中0/1的分界点,然后预处理下前缀后缀的贡献即可,代码就没写了,也是很好写的


E. Two Tanks

妙题,被思博题薄纱了,考虑到了根据总水量来一起考虑但没观察到关键性质(话说但凡认真看看样例输出可能都找到性质了)

下面讲的主要学习自知乎dalao的博客,里面有些图片看着可以帮助理解

首先考虑枚举总水量\(s\),设此时第一个桶初始时可取值区间\([L,R]\),观察或者转化题意后可以证明对应的答案一定是如下形式:

\[l,l,\cdots,l,l+1,l+2,\cdots,r-1,r,r,\cdots r \]

这里证明过程就看上面的链接吧,这里不再赘述,只能说是巧妙

然后现在问题就是怎么找出分界点\(l,r\)的值了,一种trivial的想法就是二分,不过这样复杂度会有点卡

更巧妙的方法是直接从临界的情况,第一个桶剩\(L/R\)时倒推出原来的取值点,只能说是被brainf**k了

总复杂度\(O(n\times (a+b))\)

#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=2005;
int n,a,b,v[10005],ans[N][N],sum;
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	RI i,j; for (scanf("%d%d%d",&n,&a,&b),i=1;i<=n;++i)
	scanf("%d",&v[i]),sum+=v[i]; for (i=0;i<=a+b;++i)
	{
		int L=max(0,i-b),R=min(a,i),l=L,r=R;
		auto fix=[&](CI x)
		{
			if (x<L) return L; if (x>R) return R; return x;
		};
		for (j=n;j;--j) l=max(l+v[j],L),r=min(r+v[j],R);
		int ansl=l,ansr=r; for (j=1;j<=n;++j)
		ansl=fix(ansl-v[j]),ansr=fix(ansr-v[j]);
		for (j=L;j<=R;++j) if (j<l) ans[j][i-j]=ansl;
		else if (j>r) ans[j][i-j]=ansr; else ans[j][i-j]=j-sum;
	}
	for (i=0;i<=a;++i) for (j=0;j<=b;++j) printf("%d%c",ans[i][j]," \n"[j==b]);
	return 0;
}

F. Traveling in Berland

思博题,刚开始rush了个找性质的做法然后挂了,后面想了半天发现是没特判所有的\(b_i\)都为\(2\)的情况,白白想了好久苦路西

首先注意到\(b_i\)的取值只有\(\{1,2\}\),而且我们最后加的油的总量一定是\(\sum_{i=1}^n a_i\)

因此我们转化下题意,令\(sum=2\times \sum_{i=1}^n a_i\),即假设刚开始加的全是单价为\(2\)的油,然后考虑最大化加单价为\(1\)的油的数量

基于一个贪心的想法我们很容易想到,对于每个\(b_i=1\)的点,除非它最后能一步走到终点(这种情况后面单独讨论),否则我们一定在此时把油箱加满

而对于\(b_i=2\)的点,显然只要保证此时油量能让其走到下一条边即可

因此基于这个思路,我们发现我们可以找出所有\(b_i=1\)的点\(i\)前面的那个\(b_j=1\)的点\(j\),设它们的距离为\(d\),则在点\(i\)处一般情况下要加的油量就是\(\min(d,k)\)

我们预处理出每个\(b_i=1\)的点的预期减去的值,显然大部分情况下它们的贡献都是不变的,因此把和记为\(ret\)

然后考虑起点\(st\)的不同带来的细微影响,稍加讨论发现:

  • 对于\(st\)之前的最近的\(b_{pre}=1\)的点\(pre\),要特别考虑\(pre\)的贡献,因为不能粗暴地加满了,如果可以直接到终点就把油加到刚刚好即可
  • 对于\(st\)之后的最近的\(b_{nxt}=1\)的点\(nxt\),要考虑\(st\)到\(nxt\)的贡献要在原来的基础上略作修改,而且还要分\(b_{st}\)的取值的不同有所调整,这个画图手玩一下就很好理解

然后这题就做完了,如果预处理每个点的\(pre\)和\(nxt\)复杂度就是\(O(n)\)的,不过前面写的时候脑子有点问题写了个二分,反正不影响的说

#include<cstdio>
#include<iostream>
#include<algorithm>
#define RI register int
#define CI const int&
using namespace std;
const int N=200005;
int t,n,k,a[N],b[N],pos1[N],cnt; long long pfx[N],pre[N],sum,ret;
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	for (scanf("%d",&t);t;--t)
	{
		RI i; for (scanf("%d%d",&n,&k),sum=ret=cnt=0,i=1;i<=n;++i)
		scanf("%d",&a[i]),pfx[i]=pfx[i-1]+a[i],sum+=2LL*a[i];
		for (i=1;i<=n;++i) if (scanf("%d",&b[i]),b[i]==1) pos1[++cnt]=i;
		if (!cnt)
		{
			for (i=1;i<=n;++i) printf("%lld%c",sum," \n"[i==n]); continue;
		}
		auto find_pre=[&](CI x)
		{
			return pos1[lower_bound(pos1+1,pos1+cnt+1,x)-pos1-1];
		};
		auto find_nxt=[&](CI x)
		{
			return pos1[lower_bound(pos1+1,pos1+cnt+1,x)-pos1];
		};
		auto dist=[&](CI x,CI y)
		{
			if (x<y) return pfx[y-1]-pfx[x-1]; return pfx[n]-pfx[x-1]+pfx[y-1];
		};
		for (pos1[0]=pos1[cnt],pos1[cnt+1]=pos1[1],i=1;i<=n;++i)
		if (b[i]==1) ret+=min(pre[i]=dist(find_pre(i),i),1LL*k);
		for (i=1;i<=n;++i)
		{
			long long cur=sum-ret+max(0LL,k-dist(find_pre(i),i));
			if (b[i]==1) cur-=max(0LL,k-pre[i]); else cur-=max(0LL,k-pre[find_nxt(i)]);
			printf("%lld%c",cur," \n"[i==n]);
		}
	}
	return 0;
}

Postscript

G题就那么几个人过一看就不可做,弃了弃了

标签:Educational,Rated,const,int,Codeforces,CODE,include,RI,define
From: https://www.cnblogs.com/cjjsb/p/17364238.html

相关文章

  • CodeForces-858#C 题解
    正文♦最坏时间复杂度:\(\mathcal{O}(\lvertS\rvert)\)本题十分简单,但请注意两个条件要同时满足。因为要求分割的次数越少越好,所以只要连续的辅音字母长度不大于2就不需要分割。由于辅音字母太多,只需要标记元音字母即可。#include<iostream>#include<string>#include<cst......
  • Codeforces Round 854 补题总结
    CodeforcesRound854补题总结前言昨天做这套题很不顺,今天补完题大概总结一下。总结RecentActions按题意模拟即可,考虑到前\(n\)个数一定始终在后\(m\)个数的前面,所以说当当前队列中如果没有出现\(x\)而在第\(i\)轮放进了\(x\),那么当前在队首的编号小于\(n\)的数......
  • Codeforces Round 868 Div 2
    A.A-characteristic(CF1823A)题目大意要求构造一个仅包含\(1\)和\(-1\)的长度为\(n\)的数组\(a\),使得存在\(k\)个下标对\((i,j),i<j\)满足\(a_i\timesa_j=1\)。解题思路当有\(x\)个\(1\),\(y\)个\(-1\)时,其满足条件的下标对数量为\(\frac{x(x-1)}{2}......
  • Codeforces Round 868 (Div. 2)
    Preface恭迎废物hl666终于回到了他忠诚的蓝名之位本来这场25min切完前三题而且没挂的时候感觉状态不错的,然后D被自己的一个假做法坑了1h最后ztc想出了大概的构造方法后已经来不及写了,一些细节没考虑好直接爆炸本来当时就有弃D开E的想法的,但可以E的题意在公告出来之前就已经读......
  • Codeforces Round 868 (Div. 2) A-E题解
    比赛地址这把真不在状态,麻了,看来还得再练A.A-characteristic题意:给出n和k,要求构造只含1和-1数组a,存在k对(i,j)(i≠j),有a[i]*a[j]=1Solution令构造的数组有x个1和y个-1,那么其对于答案的贡献有\[x*(x-1)/2+y*(y-1)/2\]又因为有x+y=n,所以可以转化成关于x的一元二次方程化简后......
  • Codeforces Round 867 (Div. 3)(A~D)
    目录A.TubeTubeFeed题意思路代码B.KarinaandArray题意思路代码C.BunLover题意思路代码D.Super-Permutation题意思路代码A.TubeTubeFeed题意给定时间\(t\),每个视频有一个价值\(b_i\),观看一个视频需要\(a_i\)秒,跳过一个视频需要花费\(1s\),求能观看完的价值最大......
  • Codeforces Round 867 (Div. 3)
    CodeforcesRound867(Div.3)A-TubeTubeFeed#include<bits/stdc++.h>usingnamespacestd;typedefpair<int,int>PII;typedefpair<string,int>PSI;constintN=50+5,INF=0x3f3f3f3f,Mod=1e6;constdoubleeps=1e-6;typedeflonglongll;......
  • Codeforces Round 866 (Div. 1) C. The Fox and the Complete Tree Traversal (构造)
    传送门题目大意:  给定一个有n个点的树,我们可以任意选择一个点作为起点,这个点可以跳到跟自己距离为1或者距离为2的点,已经到达的点不能再到达(最终必须回到起点),询问是否存在一种方案可以从一个点出发经过所有的点最终再回到这个点来。  输入一个整数n。紧接着输入n-1条边。大......
  • Codeforces Round 847 (Div. 3) G.Tokens on Graph (构造)
    传送门题目大意  给定一个无向图,我们定义图中有四种点,一种是黑色的点表示终点,并且黑色的点始终是1号点,一种是红色的点,一种是灰色的点,最后一种就是没有颜色的点。  游戏规则:我们必须移动任意一个灰色的点到相邻的点上,如果灰色的点移动到了红色的点上,那么我们可以移动其他灰......
  • Codeforces Round 867 (Div. 3)
    A.TubeTubeFeed#include<bits/stdc++.h>usingnamespacestd;intmain(){intq;cin>>q;while(q--){intn,t,res=-1,id=-1;cin>>n>>t;vector<int>a(n+1),b(n+1);......