zoukankan      html  css  js  c++  java
  • CF1169(div2)题解报告

    CF1169(div2)题解报告

    A

    不管

    B

    首先可以证明,如果存在解

    其中必定有一个数的出现次数大于等于(frac{m}{2})

    暴力枚举所有出现次数大于等于$frac{m}{2} $的数

    剩下的数看看有没有一个公共数即可

    由于出现次数大于等于$frac{m}{2} $的数不会太多

    所以时间复杂度应该是(O(n))

    #include<cstdio>
    #include<iostream>
    #include<queue>
    #include<algorithm>
    #include<cstring>
    #include<cctype>
    #include<vector>
    #include<ctime>
    #include<cmath>
    #define LL long long
    #define pii pair<int,int>
    #define mk make_pair
    #define fi first
    #define se second
    using namespace std;
    inline int read(){
    	int v = 0,c = 1;char ch = getchar();
    	while(!isdigit(ch)){
    		if(ch == '-') c = -1;
    		ch = getchar();
    	}
    	while(isdigit(ch)){
    		v = v * 10 + ch - 48;
    		ch = getchar();
    	}
    	return v * c;
    }
    const int N = 3e5 + 3;
    int n,r;LL ans;
    char s[N];
    int main(){
    	scanf("%s",s + 1);
    	n = strlen(s + 1);
    	r = n + 1;
    	for(int i = n - 1;i >= 1;--i){
    		r = min(r,i + 9);
    		for(int k = 1;i + 2 * k <= r;++k){
    			if(s[i] == s[i + k] && s[i] == s[i + k + k]){
    				r = min(r,i + k + k);
    				break;	
    			}
    		}
    		ans += n - r + 1;
    	}
    	cout << ans;
    	return 0;
    }
    
    

    C

    所有题目先考虑答案是否就有单调性

    这种最优解问题且答案具有单调性的题目先考虑二分答案

    然后看卡能否贪心判断可行性

    这道题我们二分枚举答案之后

    我们肯定是贪心的让每个数都尽量小

    对于一个数

    如果他能在二分的答案的步数之内达到最小值就去

    如果不行看看是否合法,判断一下是否无解

    因为我们肯定不会让一个满足条件数再变大,那样只会不优

    #include<cstdio>
    #include<iostream>
    #include<queue>
    #include<algorithm>
    #include<cstring>
    #include<cctype>
    #include<vector>
    #include<ctime>
    #include<cmath>
    #define LL long long
    #define pii pair<int,int>
    #define mk make_pair
    #define fi first
    #define se second
    using namespace std;
    const int N = 3e5 + 3;
    int a[N];
    int f[N];
    int pre[N];
    int n,m;
    inline int read(){
    	int v = 0,c = 1;char ch = getchar();
    	while(!isdigit(ch)){
    		if(ch == '-') c = -1;
    		ch = getchar();
    	}
    	while(isdigit(ch)){
    		v = v * 10 + ch - 48;
    		ch = getchar();
    	}
    	return v * c;
    }
    int ans = 0x3f3f3f3f;
    inline bool check(int mid){
    	for(int i = 1;i <= n;++i) pre[i] = a[i];
    	pre[1] = m - a[1] > mid ? a[1] : 0;
    	for(int i = 2;i <= n;++i){
    		if(a[i] < pre[i - 1]){
    			if(pre[i - 1] > a[i] + mid) return 0;
    			pre[i] = pre[i - 1];	
    		}
    		else{
    			if(a[i] == pre[i - 1]) pre[i] = a[i];
    			if(a[i] > pre[i - 1]) pre[i] = m - a[i] + pre[i - 1] > mid ? a[i] : pre[i - 1];
    		}
    	}
    	return 1;
    }
    int main(){
    	n = read(),m = read();
    	for(int i = 1;i <= n;++i) a[i] = read();
    	int l = 0,r = 10000000,ans;
    	while(l <= r){
    		int mid = (l + r) >> 1;
    		if(check(mid)) r = mid - 1,ans = mid;
    		else l = mid + 1;
    	}
    	cout << ans;
    	return 0;
    }
    
    

    D

    神仙暴力题Orz

    自己搞一棵01Trie试一试,发现长度为(9)或者以上的区间一定会满足题目中的要求

    那么我们对于每一个固定的左端点(l)

    我们都找一个离它的最近的满足条件的(r), (rin[l,l+9])

    那么右端点([r,n])都是合法的

    在枚举的时候我们发现

    对于一个(l),(l + 1)的满足条件的最近端点一定在(l)的满足条件的最右端点的左边

    因为([l+r,r_{l + 1}])也在(l)包含的区间内

    所以我们每一次都继承(l +_1)的答案

    看看能否继续变优

    #include<cstdio>
    #include<iostream>
    #include<queue>
    #include<algorithm>
    #include<cstring>
    #include<cctype>
    #include<vector>
    #include<ctime>
    #include<cmath>
    #define LL long long
    #define pii pair<int,int>
    #define mk make_pair
    #define fi first
    #define se second
    using namespace std;
    inline int read(){
    	int v = 0,c = 1;char ch = getchar();
    	while(!isdigit(ch)){
    		if(ch == '-') c = -1;
    		ch = getchar();
    	}
    	while(isdigit(ch)){
    		v = v * 10 + ch - 48;
    		ch = getchar();
    	}
    	return v * c;
    }
    const int N = 3e5 + 3;
    int n,r;LL ans;
    char s[N];
    int main(){
    	scanf("%s",s + 1);
    	n = strlen(s + 1);
    	r = n + 1;
    	for(int i = n - 1;i >= 1;--i){
    		r = min(r,i + 9);
    		for(int k = 1;i + 2 * k <= r;++k){
    			if(s[i] == s[i + k] && s[i] == s[i + k + k]){
    				r = min(r,i + k + k);
    				break;	
    			}
    		}
    		ans += n - r + 1;
    	}
    	cout << ans;
    	return 0;
    }
    
    

    E

    这道题是真的没思路

    我们可以写一个(n^2)的代码

    bool check(int x,int y){
        int v1 = a[x];
        for(int i = x + 1;i < y;++i)
            if(v1 & a[i]) v1 |= a[i];
        return v1 & a[y];
    }
    

    就是说我们考虑当前的子集

    如果这个点能够和某一个元素连边

    他一定可以从(x)转移过来

    那么我们就分位考虑

    在线段树上维护这个东西

    每个节点维护(19)个变量

    表示包含(2^k)的集合从左边传过来,最终会变成什么样

    	inline void pushup(int u){
    		for(int i = 0;i < 19;++i){
    			int v = a[a[u].lc].sum[i];
    			a[u].sum[i] = v;
    			for(int j = 0;j < 19;++j)
    				if(v & (1 << j)) a[u].sum[i] |= a[a[u].rc].sum[j];
    			a[u].sum[i] |= a[a[u].rc].sum[i];
    		}	
    	}
    

    pushup大约这么写,注意这里有一个细节,就是我们判断左边是否有这一位的时候

    应该用原来的值(我代码中的(v))判断,而不能够用更新之后的(a[u].sum[i])去判断

    这样很明显会错,会引入不合法的情况

    查阅答案就和这个类似了

    #include<cstdio>
    #include<iostream>
    #include<queue>
    #include<algorithm>
    #include<cstring>
    #include<cctype>
    #include<vector>
    #include<ctime>
    #include<cmath>
    #define LL long long
    #define pii pair<int,int>
    #define mk make_pair
    #define fi first
    #define se second
    using namespace std;
    const int N = 3e5 + 3;
    int b[N];
    int n,q,rt;
    int ans;
    inline int read(){
    	int v = 0,c = 1;char ch = getchar();
    	while(!isdigit(ch)){
    		if(ch == '-') c = -1;
    		ch = getchar();
    	}
    	while(isdigit(ch)){
    		v = v * 10 + ch - 48;
    		ch = getchar();
    	}
    	return v * c;
    }
    struct tree{
    	struct node{
    		int lc;
    		int rc;
    		int sum[21];
    	}a[N << 1];
    	int t;
    	inline void pushup(int u){
    		for(int i = 0;i < 19;++i){
    			int v = a[a[u].lc].sum[i];
    			a[u].sum[i] = v;
    			for(int j = 0;j < 19;++j)
    				if(v & (1 << j)) a[u].sum[i] |= a[a[u].rc].sum[j];
    			a[u].sum[i] |= a[a[u].rc].sum[i];
    		}	
    	}
    	inline void build(int &u,int l,int r){
    		if(!u) u = ++t;
    		if(l == r){
    			for(int i = 0;i < 19;++i)
    				if(b[l] & (1 << i)) a[u].sum[i] = b[l];
    			return ;
    		}
    		int mid = (l + r) >> 1;
    		build(a[u].lc,l,mid);build(a[u].rc,mid + 1,r);
    		pushup(u);
    	}
    	inline bool query(int u,int l,int r,int ll,int rr,int w){
    		if(ans & w) return 1;
    		if(ll > rr) return 0;
    		if(l == ll && r == rr){
    			int v = 0;
    			for(int i = 0;i < 19;++i) if(ans & (1 << i)) v |= a[u].sum[i];
    			ans |= v;
    			return ans & w;
    		}
    		int mid = (l + r) >> 1;
    		if(rr <= mid) return query(a[u].lc,l,mid,ll,rr,w);
    		else if(ll > mid) return query(a[u].rc,mid + 1,r,ll,rr,w);
    		else return query(a[u].lc,l,mid,ll,mid,w) | query(a[u].rc,mid + 1,r,mid + 1,rr,w); 
    	}
    }T;
    int main(){
    //	system("pause");
    	n = read(),q = read();
    	for(int i = 1;i <= n;++i) b[i] = read();
    	T.build(rt,1,n);
    	for(int i = 1;i <= q;++i){
    		int x = read(),y = read();
    		if(x == 0 || y == 0) printf("Fou
    ");
    		else{
    		//	if(x == y) printf("Shi
    ");
    		//	else {
    				ans = b[x];
    				if(T.query(rt,1,n,x + 1,y - 1,b[y])) printf("Shi
    ");
    				else printf("Fou
    ");
    		//	}
    		}	
    	}
    //	system("pause");
    	return 0;
    }
    

    这样的时间复杂度为(O(nlog^2(n)))

    听说这道题一个log的DP做法,先咕一咕

  • 相关阅读:
    Python-sokect 示例
    Python装饰器
    javascript权威指南第22章高级技巧
    javascript权威指南第21章 Ajax和Comet
    javascript权威指南第20章 JSON
    javascript权威指南第17章 错误异常处理
    javascript权威指南第16章 HTML5脚本编程
    Bootstrap 表单布局示例
    javascript权威指南第15章 使用Canvas绘图
    贪心算法学习笔记
  • 原文地址:https://www.cnblogs.com/wyxdrqc/p/11397266.html
Copyright © 2011-2022 走看看