CF Round 72 (Rated for Div. 2) (CDE)

题目链接

The Number Of Good Substrings(暴力)

题意:

给定一个二进制串,问有多少个子串形成的十进制值等于子串长度。
( l e n < = 1 e 5 ) (len<=1e5)

思路:

直接暴力求解即可,我们枚举每一个1的位置,向后延伸20的长度,因为区间不会超过 2 20 2^{20} 对于前导零我们可以通过预处理每一个 1 1 前面的连续 0 0 的个数,在循环是判断是否可以达到即可累加答案。

代码:

#include <bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int T;
char s[N];
int gs[N];
int ans=0,n;
void cl(int pos,int sum){
	int temp=0;
	for(int i=pos;i<=pos+19;i++){
		if(i>n)break;
		temp=temp*2+s[i]-'0';
		if(temp==i-pos+1)ans++;
		else if(temp>i-pos+1&&temp<=i-pos+1+gs[pos])ans++;
	}
}
int main()
{
	scanf("%d",&T);
	while(T--){
		scanf("%s",s+1);n=strlen(s+1);
		ans=0;
		int temp=0;
		for(int i=1;i<=n;i++){
			if(s[i]=='0')temp++;
			else {
				gs[i]=temp;temp=0;
			}
		}
		for(int i=1;i<=n;i++){
			if(s[i]=='1'){
				cl(i,gs[i]);
			}
		}
		cout<<ans<<endl;
	}
}

D. Coloring Edges(思维)

题意:

给一个有向图,要求给边染色,要求每一个环不能同色,问至少需要几种颜色,输出任意方案。

思路:

可以先判断有没有环,如果没有环,那么答案就是 1 1 每一个边都输出 1 1 即可,如果出现环,我们其实只要用两种颜色即可染色,我们观察怎么才能让一个环不同色,看到别人一个很好的方法,对于一个边 u v u \to v ,当 u &gt; v u&gt;v 时染 1 1 , u &lt; v u&lt;v 时染2那么一个环不可能同色,很巧妙。

代码:

#include <bits/stdc++.h>
using namespace std;
const int N=5e3+10;
struct node{
	int v,id;
	node(int a=0,int b=0){v=a,id=b;}
};
vector<node>e[N];
int du[N],n,m;
bool pd(){
	queue<int>q;int cnt=0;
	for(int i=1;i<=n;i++)if(!du[i])q.push(i),cnt++;
	while(!q.empty()){
		int now=q.front();q.pop();
		for(node t:e[now]){
			if(--du[t.v]==0){
				q.push(t.v);
				cnt++;
			}
		}
	}
	return cnt!=n;
}
int bj[N];
int vis[N];
void dfs(int u,int pre){
	if(vis[u]==1)return ;
	vis[u]=1;
	for(node now:e[u]){
		bj[pre]=1;bj[now.id]=2;
		dfs(now.v,now.id);
	}
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1,a,b;i<=m;i++){
		scanf("%d%d",&a,&b);
		du[b]++;e[a].push_back(node(b,i));
	}
	if(pd()){
		for(int i=1;i<=n;i++){
			for(node now:e[i]){
				if(i<now.v){
					bj[now.id]=1;
				}
				else bj[now.id]=2;
			}
		}
		cout<<2<<endl;
		for(int i=1;i<=m;i++)cout<<bj[i]<<" ";
		cout<<endl;
	}
	else{
		cout<<1<<endl;
		for(int i=1;i<=m;i++)cout<<1<<" ";
		cout<<endl;
	}
}

E. Sum Queries?(线段树)

题意:

给定应该数字的序列,定义合法的数字集合 { S } \{S\} 为集合内所有数字的和每一位都存在集合内的一个数字与其对应位置相同。
要求实现两种操作:
1.将序列 p o s pos 位置的值变为 v a l val
2.查询 ( L , R ) (L,R) 区间,要求从区间内选取数字之和最小的数字构成不合法的集合,输出数字之和。

思路:

首先观察如何构造不合法序列,发现两个数字若存在一位都不为 0 0 ( a ! = ( a + b ) % 10 &amp; &amp; b ! = ( a + b ) % 10 ) (a != (a+b)\%10 \&amp;\&amp; b!=(a+b)\%10) 那么这两个数字就可以构成不合法的,要求数字和最小,那么我们必然选择两个和最小的数字(大于2个的集合可以转化为2个数字的集合),我们使用线段树维护区间的每一位的不为零的最小值和次小值即可,查询时只要对最小值和次小值之和取一个最小。

代码:

#include <bits/stdc++.h>
#define ll long long
#define inf 2e9+10
using namespace std;
const int N=2e5+10;
int n,m;
int ls[N*4],rs[N*4];
struct node{
	int mi1[11],mi2[11];
}e[N*4];
node operator + (const node &a,const node &b){
	node c;
	for(int i=1;i<=10;i++){
		c.mi1[i]=min(a.mi1[i],b.mi1[i]);
		if(a.mi1[i]<b.mi1[i])c.mi2[i]=min(a.mi2[i],b.mi1[i]);
		else c.mi2[i]=min(a.mi1[i],b.mi2[i]);
	}
	return c;
}
int arr[N];
void built(int x,int l,int r){
	ls[x]=l,rs[x]=r;
	if(l==r){
		int temp=arr[l];
		for(int i=1;i<=10;i++){
			e[x].mi1[i]=inf,e[x].mi2[i]=inf;
			int v=temp%10;temp/=10;
			if(v)e[x].mi1[i]=arr[l];
		}
		return ;
	}
	int mid=(l+r)/2;
	built(x*2,l,mid);built(2*x+1,mid+1,r);
	e[x]=e[2*x]+e[2*x+1];
}	
void add(int x,int pos,int v){
	if(ls[x]==rs[x]){
		int temp=v;
		for(int i=1;i<=10;i++){
			e[x].mi1[i]=e[x].mi2[i]=inf;
			int t=temp%10;temp/=10;
			if(t)e[x].mi1[i]=v;
		}
		return ;
	}
	int mid=(ls[x]+rs[x])/2;
	if(pos<=mid)add(2*x,pos,v);
	else add(2*x+1,pos,v);
	e[x]=e[2*x]+e[2*x+1];
}
node query(int x,int LL,int RR){
	if(ls[x]>=LL&&rs[x]<=RR){
		return e[x];
	}
	int mid=(ls[x]+rs[x])/2;
	if(RR<=mid)return query(2*x,LL,RR);
	else if(LL>mid)return query(2*x+1,LL,RR);
	else return query(2*x,LL,RR)+query(2*x+1,LL,RR);
}
int op,l,r;
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%d",&arr[i]);
	built(1,1,n);
	while(m--){
		scanf("%d%d%d",&op,&l,&r);
		if(op==1){
			add(1,l,r);
		}else{
			node t1=query(1,l,r);
			ll ans=inf;
			for(int i=1;i<=10;i++){
				ans=min(ans,1ll*t1.mi1[i]+t1.mi2[i]);
			}
			if(ans>=inf)ans=-1;
			printf("%d\n",ans);
		}
	}
}

猜你喜欢

转载自blog.csdn.net/qq_40400202/article/details/100577445