zoukankan      html  css  js  c++  java
  • Codeforces Round #683 (Div. 2, by Meet IT) 题解&总结

    值得纪念。

    但以后不会再有了QAQ

    A

    其它的增高相当于自己降低。所以按顺序输出(1)(n)即可。

    (由于一开始看反了导致挂了一次……)

    B

    两点间随意找一条路径操作,路径中间的点没有影响,只会影响端点。

    全局找任意对数将其符号取反。贪心即可。

    C

    先从大到小排序,能选就选。由于要求的下界是上界的一半,从大往小选,不存在少选一个大的,多选几个小的才能满足的情况。

    (似乎不排序也能做)

    D

    朴素DP。直接设(f_{i,j}),也就是普通的LCS问题改点细节而已。

    E

    D到E花了1.5h,E到F1花了不到0.5h。我在干嘛……

    https://www.cnblogs.com/jz-597/p/13986661.html

    F

    显然全局众数也是最优区间的众数之一(否则考虑最优区间扩张的过程,必定存在一次局部众数和全局众数的出现次数相等)。

    找出全局众数,分别枚举每一个数,变成如下问题:全局众数出现的位置为(+1),这个数出现的位置为(-1),其它位置为(0),求最长的和为(0)的区间。

    第一档部分分直接开个桶来维护。时间(O(100n))。贴代码:

    using namespace std;
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define N 200005
    int n,m;
    int a[N];
    int s[N][101];
    int p[N];
    int buc[N*2];
    void upd(int &a,int b){
    	if (a==-1) a=b;
    }
    int main(){
    //	freopen("in.txt","r",stdin);
    	scanf("%d",&n);
    	for (int i=1;i<=n;++i){
    		scanf("%d",&a[i]);
    		memcpy(s[i],s[i-1],sizeof s[i]);
    		s[i][a[i]]++;
    	}
    	int id=1,mx=s[n][1];
    	for (int i=2;i<=100;++i)
    		if (s[n][i]>mx)
    			mx=s[n][i],id=i;
    		else if (s[n][i]==mx)
    			id=-1;
    	if (id==-1){
    		printf("%d
    ",n);
    		return 0;
    	}
    	p[0]=0;
    	for (int i=1;i<=n;++i)
    		if (a[i]==id)
    			p[++m]=i;
    	p[++m]=n+1;
    	memcpy(s[n+1],s[n],sizeof s[n]);
    	int ans=0;
    	for (int i=1;i<=100;++i){
    		if (i==id)
    			continue;
    		memset(buc,255,sizeof buc);
    		for (int j=0;j<=m;++j){
    //			if (j==3)
    //				j=3;
    //			printf("query(%d)
    ",s[p[j]][i]-j);
    			if (buc[s[p[j]][i]-j +N]!=-1)
    				ans=max(ans,p[j]-buc[s[p[j]][i]-j +N]-1);
    //			printf("upd(%d,%d)
    ",s[p[j]][i]-j-1,p[j]);
    			upd(buc[s[p[j]][i]-j-1 +N],p[j]);
    		}
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    

    对于第二档,题解做法:如果这个数的出现次数(|V|>sqrt n),那么用上述方法(O(n))做;否则,对于这个数的每个出现位置(V_i),提取出左右离它最近的全局众数,一共要做(O(|V|))个位置,每个位置要么是一个(-1)或一段(+1)。可以直接(O(|V|^2))。总时间(O(nsqrt n))

    其实也可以做到(O(nlg n))。用线段树维护区间的前缀最大值和最小值。当需要找一个值的的第一次出现位置的时候,由于每次只会(+1)(-1),是连续的,如果这个值在最小值最大值之间,就一定存在。那么在线段树上二分即可。

    都没写。


    感觉这次发挥比较好。

    原因大概有:

    1. 这次咖啡选择在晚餐后喝,比赛期间精神饱满,肾上腺素激增,上厕所时能感受到心跳,打题时感觉到右臂的动脉在动。(我不是在吹)。
    2. 这次题目比较适合我发挥,不像上次div2那样全场构造。
    3. 2:30的写题时间,第一次div2切了超过4题。
    4. 秒切了不知道为什么没什么人写的F1。

    当然了这次也存在一些败笔。在想题的时候(尤其是E题),绕了很长的弯子,中间想了个可能不靠谱的阴间做法,交了一遍自然挂了。感觉应该要更严谨一些,那种做法应该被ban掉的。

    div1我来啦!

  • 相关阅读:
    Codeforces Round #344 (Div. 2) C. Report 其他
    Codeforces Round #344 (Div. 2) B. Print Check 水题
    Codeforces Round #344 (Div. 2) A. Interview 水题
    8VC Venture Cup 2016
    CDOJ 1280 772002画马尾 每周一题 div1 矩阵快速幂 中二版
    CDOJ 1280 772002画马尾 每周一题 div1 矩阵快速幂
    CDOJ 1279 班委选举 每周一题 div2 暴力
    每周算法讲堂 快速幂
    8VC Venture Cup 2016
    Educational Codeforces Round 9 F. Magic Matrix 最小生成树
  • 原文地址:https://www.cnblogs.com/jz-597/p/13987051.html
Copyright © 2011-2022 走看看