Codeforces Round #337 (Div. 2) ABCDE

Pasha and Stick

        简单分类讨论。

#include <bits/stdc++.h>

using namespace std;

#define ll long long

int main(){
	int n;
	cin>>n;
	if(n&1){
		cout<<0<<endl;
	}else{
		n>>=1;
		if(n&1){
			cout<<n/2<<endl;
		}else{
			cout<<n/2-1<<endl;
		}
	}
	return 0;	
}

Vika and Squares

        贪心。就是找最小值之间的最大距离,我实现的时候把数组copy了一份放在后面,这样处理比较简单。

#include <bits/stdc++.h>


using namespace std;

#define ll long long

int a[400010];

int main(){
	int n;
	cin>>n;
	
	int MIN=1e9+10;
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		MIN=min(MIN,a[i]);
	}
	
	for(int i=1;i<=n;i++){
		a[i+n]=a[i];
	}
	
	int pre=1;
	int len=0;
	for(int i=1;i<=n*2;i++){
		if(a[i]==MIN){
			len=max(len,i-pre-1);
			pre=i;
		}
	}
	
	ll ans = (ll)n*MIN+len;
	
	cout<<ans<<endl;
	
	return 0;	
}

Harmony Analysis

        构造题。首先k=1很容易构造出来。k=x+1其实是由4个k=x构成的,用4个k=x拼起来后,把其中一个取反即可。

#include <bits/stdc++.h>


using namespace std;

#define ll long long

int a[1111][1111];

int main(){
	
	int k;
	cin>>k;
	
	int n = 1<<k;
	
	a[1][1]=1;
	a[1][2]=1;
	a[2][1]=1;
	a[2][2]=0;
	
	for(int i=2;i<=9;i++){
		int half = 1<<(i-1);
		for(int j=1;j<=half;j++){
			for(int kk=1;kk<=half;kk++){
				a[j][kk+half]=!a[j][kk];
			}
		}
		//
		for(int j=1;j<=half;j++){
			for(int kk=1;kk<=half;kk++){
				a[j+half][kk]=a[j][kk];
			}
		}
		//
		for(int j=1;j<=half;j++){
			for(int kk=1;kk<=half;kk++){
				a[j+half][kk+half]=a[j][kk];
			}
		}
	}
	
	
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(a[i][j]){
				printf("+");
			}else{
				printf("*");
			}
		}cout<<endl;
	}

	return 0;	
}

Vika and Segments

        这种题一看就知道是用map乱搞。大体思路是分开横向和纵向,先计算横向的,然后对于每个纵向的,看它穿过了多少个横向的,减去重叠部分即可。

        一步一步来,首先是要把横向和纵向分开,同向的里面也有重叠的,把重叠的合并。然后简单计算一下所有横向的结果。计算完后,从左到右处理纵向的。对于枚举的每个纵向条条,维护有哪些横向的条条的横坐标包含了纵向条条的横坐标(我利用了map和priority_queue维护,具体见代码),然后利用树状数组(当然,事先离散化了Y坐标)计算它穿越了多少横向条条,把重叠部分减去即可。

#include <bits/stdc++.h>


using namespace std;

#define ll long long

int n;

struct hor{
	int x1,x2;
	int y;
	bool ban;
	bool operator<(const hor& other)const{
		if(y!=other.y){
			return y<other.y;
		}
		if(x1!=other.x1){
			return x1<other.x1;
		}
		return x2<other.x2;
	}
}hors[100010];

bool cmpx1(hor a,hor b){
	return a.x1<b.x1;
}

struct cmpx2{	//比较下x2 
	bool operator()(hor a,hor b){
		return a.x2 > b.x2;
	}
};


struct ver{
	int y1,y2;
	int x;
	bool ban;
	bool operator<(const ver& other)const{
		if(x!=other.x){
			return x<other.x;
		}
		if(y1!=other.y1){
			return y1<other.y1;
		}
		return y2<other.y2;
	}
}vers[100010];

int hcnt=0;
int vcnt=0;

map<int,int> ymp;	//用于离散化 

int c[200010];
inline int lowbit(const int &x){
	return x&(-x);
}

void update(int x,int val){
	while(x<200010){
		c[x]+=val;
		x+=lowbit(x);
	}
}

int query(int x){

	int ans = 0;
	while(x){
		ans+=c[x];
		x-=lowbit(x);
	}
	return ans;
}

int main(){
	
	
	cin>>n;
	
	for(int i=1;i<=n;i++){
		int x1,y1,x2,y2;
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		if(x1>x2)swap(x1,x2);
		if(y1>y2)swap(y1,y2);
		
		if(x1==x2){
			vers[vcnt].y1=y1;
			vers[vcnt].y2=y2;
			vers[vcnt].x =x1;
			vcnt++;
		}else{
			hors[hcnt].x1=x1;
			hors[hcnt].x2=x2;
			hors[hcnt].y =y1;
			hcnt++;
		}
		ymp[y1]=0;
		ymp[y2]=0;
	}
	sort(vers,vers+vcnt);
	sort(hors,hors+hcnt);
	
	//离散化
	int kk = 1;
	for(map<int,int>::iterator it = ymp.begin();it!=ymp.end();it++){
		it->second = kk++;
	} 
	
	//同向的合并 
	for(int i=1;i<vcnt;i++){
		if(vers[i].x == vers[i-1].x){
			if(vers[i].y1<=vers[i-1].y2){
				vers[i].y1 = vers[i-1].y1;
				vers[i].y2 = max(vers[i].y2,vers[i-1].y2);
				vers[i-1].ban=1;
			}
		}
	}
	for(int i=1;i<hcnt;i++){
		if(hors[i].y == hors[i-1].y){
			if(hors[i].x1<=hors[i-1].x2){
				hors[i].x1 = hors[i-1].x1;
				hors[i].x2 = max(hors[i].x2,hors[i-1].x2);
				hors[i-1].ban=1;
			}
		}
	}
	
	ll ans = 0;
	
	//计算横向 
	for(int i=0;i<hcnt;i++){
		if(!hors[i].ban){
			ans+=hors[i].x2-hors[i].x1+1;	
		}
	}
	
	//处理纵向 
	sort(hors,hors+hcnt,cmpx1);
	priority_queue<hor,vector<hor>,cmpx2> que;
	int k=0;
	for(int i=0;i<vcnt;i++){
		if(vers[i].ban)continue;
		//左边界符合的加入 
		while(hors[k].x1 <= vers[i].x && k < hcnt){
			if(!hors[k].ban){
				update( ymp[hors[k].y],1);
				que.push(hors[k]);
			}
			k++;
		}
		
		//右边界不符合的移除 
		while(que.size()){
			hor tmp = que.top();
			if(tmp.x2 < vers[i].x){
				que.pop();
				update( ymp[tmp.y],-1);
			}else{
				break;
			}
		}

		int q1 = query( ymp[vers[i].y1] - 1);
		int q2 = query( ymp[vers[i].y2] );
		ans+=(vers[i].y2 - vers[i].y1 + 1);
		ans-=(q2-q1);
		
	}
	
	cout<<ans<<endl;
	
	return 0;	
}


Alphabet Permutations

        线段树。线段树维护的是每个位置的字符,以及区间上,字符x紧接着字符y的次数(最多10*10组x,y)。对于每次询问,相当于得到了一个“字典序”,在线段树中查询,共有多少组相邻的字符xy,x的字典序小于y,记为sum,答案就是n-sum。因为n-repeat肯定是满足的,出现一次上述情况,可以省去一次。

#include <bits/stdc++.h>


using namespace std;

int n,m,k;
char str[200010];


struct node{
	int l,r;
	int ch;
	int lazy;
	int val[10][10];
}tree[800010];



void push_up(int x){
	if(tree[x].l==tree[x].r)return;
	node& lson = tree[x<<1];
	node& rson = tree[(x<<1)|1];
	for(int i=0;i<k;i++){
		for(int j=0;j<k;j++){
			tree[x].val[i][j] = lson.val[i][j]+rson.val[i][j];
		}
	}
}

int queryCh(int x,int pos){
	if(~tree[x].lazy){
		return tree[x].lazy;
	}
	if(tree[x].l==tree[x].r){
		return tree[x].ch;
	}
	int mid = (tree[x].l+tree[x].r)>>1;
	if(pos<=mid){
		return queryCh(x<<1,pos);
	}else{
		return queryCh((x<<1)|1,pos);
	}
}

void push_down(int x,int ch){
	if(tree[x].l == tree[x].r){
		tree[x].lazy = -1;
		return;
	}
	node& lson = tree[x<<1];
	node& rson = tree[(x<<1)|1];
	lson.lazy = rson.lazy = tree[x].lazy;
	tree[x].lazy = -1;
	lson.ch = tree[x].ch;
	rson.ch = tree[x].ch;
	for(int i=0;i<k;i++){
		for(int j=0;j<k;j++){
			lson.val[i][j] = 0;
			rson.val[i][j] = 0;
		}
	}
}

void updateVal(int x,int pos){
	if(tree[x].l==tree[x].r){
		if(tree[x].l){
			memset(tree[x].val,0,sizeof(tree[x].val));
			int left = queryCh(1,tree[x].l-1);
			int ch = queryCh(1,tree[x].l);
			if(left!=ch){
				tree[x].val[left][ch] = 1;
			}
		}
		return;
	}
	if(~tree[x].lazy){
		push_down(x,tree[x].lazy);
	}
	int mid = (tree[x].l+tree[x].r)>>1;
	if(pos<=mid){
		updateVal(x<<1,pos);
	}else{
		updateVal((x<<1)|1,pos);
	}
	push_up(x);
}

void build_tree(int x,int l,int r){
	tree[x].l = l;
	tree[x].r = r;
	tree[x].lazy = -1;
	if(l==r){
		if(l)tree[x].val[str[l-1]-'a'][str[l]-'a'] = 1;
		tree[x].ch = str[l]-'a';
		return;
	}
	int mid = (l+r)>>1;
	build_tree(x<<1,l,mid);
	build_tree((x<<1)|1,mid+1,r);
	push_up(x);
}



void update(int x,int l,int r,int ch){
	if(l==tree[x].l && r==tree[x].r){
		tree[x].lazy = ch;
		tree[x].ch = ch;
		memset(tree[x].val,0,sizeof(tree[x].val));
		return;
	}
	if(~tree[x].lazy){
		push_down(x,tree[x].lazy);
	}
	int mid = (tree[x].l+tree[x].r)>>1;
	if(mid>=r){
		update(x<<1,l,r,ch);
	}else{
		if(mid<l){
			update((x<<1)|1,l,r,ch);
		}else{
			update(x<<1,l,mid,ch);
			update((x<<1)|1,mid+1,r,ch);
		}
	}
	push_up(x);
}


int ans[11][11];
void query(int x,int l,int r){
	if(l==tree[x].l && r==tree[x].r){
		for(int i=0;i<k;i++){
			for(int j=0;j<k;j++){
				ans[i][j] += tree[x].val[i][j];
			}
		}
		return;
	}
	if(~tree[x].lazy){
		push_down(x,tree[x].ch);
	}
	int mid = (tree[x].l+tree[x].r)>>1;
	if(mid>=r){
		query(x<<1,l,r);
	}else{
		if(mid<l){
			query((x<<1)|1,l,r);
		}else{
			query(x<<1,l,mid);
			query((x<<1)|1,mid+1,r);
		}
	}
}

void Q(int l,int r){
	memset(ans,0,sizeof(ans));
	query(1,l,r);
}

int main(){
	
	cin>>n>>m>>k;
	scanf("%s",str);
	build_tree(1,0,n-1);
	
	while(m--){
		int op;
		scanf("%d",&op);
		if(op==1){	//update
			int l,r;
			char chs[2];
			scanf("%d%d%s",&l,&r,chs);
			update(1,l-1,r-1,chs[0]-'a');
			if(l-1)updateVal(1,l-1);
			updateVal(1,r);
		}else{		//query
			char per[11];
			scanf("%s",per);
			Q(0,n-1);
			
			bool tmp[11][11] = {0};
			for(int i=0;i<k;i++){
				for(int j=i+1;j<k;j++){
					tmp[per[i]-'a'][per[j]-'a']=1;
				}
			}
			int res = n;
			for(int i=0;i<k;i++){
				for(int j=0;j<k;j++){
					if(tmp[i][j]){
						res-=ans[i][j];
					}
				}
			}
			cout<<res<<endl;
		}
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值