Codeforces Round #573 (Div. 2) 解题报告

A.Tokitsukaze and Enhancement

http://codeforces.com/contest/1191/problem/A

本题主要考察选手是否会写代码,穷举即可。

#include<bits/stdc++.h>
using namespace std;

int main(){
	int x;
	cin>>x;
	x%=4;
	if(x==1)cout<<"0 A"<<endl;
	if(x==3)cout<<"2 A"<<endl;
	if(x==2)cout<<"1 B"<<endl;
	if(x==0)cout<<"1 A"<<endl;
} 

B.Tokitsukaze and Mahjong

http://codeforces.com/contest/1191/problem/B

本题考察选手是否有写小模拟的能力,分类讨论模拟即可。

#include<bits/stdc++.h>
using namespace std;
int a[3];
int main(){
	string s1,s2,s3;
	cin>>s1>>s2>>s3;
	if(s1[1]==s2[1]&&s1[1]==s3[1]){
		a[0]=s1[0];
		a[1]=s2[0];
		a[2]=s3[0];
		sort(a,a+3);
		if(a[0]==a[2])cout<<0<<endl;
		else if(a[0]==a[1]-1&&a[1]==a[2]-1)cout<<0<<endl;
		else if(a[0]==a[1]||a[1]==a[2])cout<<1<<endl;
		else if(a[0]==a[1]-1||a[1]==a[2]-1)cout<<1<<endl;
		else if(a[0]==a[1]-2||a[1]==a[2]-2)cout<<1<<endl;
		else cout<<2<<endl;
	}else{
		if(s1[1]!=s2[1]){
			if(s1[1]==s3[1])swap(s2,s3);
			else if(s2[1]==s3[1])swap(s1,s3);
		}
		if(s1[1]!=s2[1])cout<<2<<endl;
		else{
			a[0]=s1[0];
			a[1]=s2[0];
			sort(a,a+2);
			if(a[0]==a[1]||a[0]==a[1]-1||a[0]==a[1]-2)cout<<1<<endl;
			else cout<<2<<endl;
		}
	}
}

PS:学会打麻将真的很重要,建议在集训队招新条件中加入“会打麻将”。

C.Tokitsukaze and Discard Items

http://codeforces.com/contest/1191/problem/C

仍然是模拟题。但是有一个地方要注意,在翻页的地方,不能一页一页翻,不然可能会T(比如我)。直接用整除+余数O(1)定位到跳到的位置。

即:

    LL rmn=lst%k;
	st=(p[c]/k)*k+rmn;
	if(lst<p[c])lst+=k;

另:开longlong。

#include<bits/stdc++.h>
using namespace std;
#define LL long long
LL p[100005];
LL n,m,k;
LL cnt=0;
LL sv=0;
int main(){
	scanf("%lld%lld%lld",&n,&m,&k);
	for(LL i=0;i<m;++i)scanf("%lld",&p[i]);
	LL lst=k;
	LL c=0;
	while(c<m){
		if(p[c]<=lst){
			++c;
			++sv;
		}else if(sv){
			lst+=sv;
			sv=0;
			++cnt;
		}else{
			LL rmn=lst%k;
			lst=(p[c]/k)*k+rmn;
			if(lst<p[c])lst+=k;
		}
	}
	if(sv)++cnt;
	cout<<cnt<<endl;
}

D.Tokitsukaze, CSL and Stone Game

http://codeforces.com/contest/1191/problem/D

如果先手选手第一步动完不立刻输掉的话,最后所有的石子会变成0-1-2-…-(n-1),因为不能有任何两列相同。所以分两种情况讨论,如果先手第一步不输,那么根据初末状态的奇偶性可以判断;接下来只要考虑第一步直接失败的情况。

我们对石子个数排序,有以下三种情况会暴毙:
1.存在两对或以上相同的石子数(包括三连),这样怎么搞选完都有至少一对相同;
2.存在一对相同的且存在一堆石子比这堆石子刚好少一个,这样选这对相同的就会出现一对新的相同的;
3.存在两个或以上0,这样你随便怎么搞,选完还是有至少两个0。

#include<bits/stdc++.h>
using namespace std;

#define LL long long
int n;
LL a[100005];
int flag=0;

int main(){
	scanf("%d",&n);
	for(int i=0;i<n;++i)scanf("%lld",&a[i]);
	sort(a,a+n);
	for(int i=0;i<n-1;++i){
		if(a[i]==a[i+1]){
			if(i&&(a[i]==a[i-1]||a[i]==a[i-1]+1)){
				cout<<"cslnb"<<endl;
				return 0;
			}
			if(a[i]==0){
				cout<<"cslnb"<<endl;
				return 0;
			}
			if(flag++){
				cout<<"cslnb"<<endl;
				return 0;
			}
		}
	}
	LL sum=0;
	for(int i=0;i<n;++i)sum=(sum+a[i]-i)%2;
	cout<<(sum?"sjfnb":"cslnb")<<endl;
}

F.Tokitsukaze and Strange Rectangle

http://codeforces.com/contest/1191/problem/F

看到这个数据规模应该很容易想到nlogn数据结构按顺序递推logn求取状态参量。

因为向上开口,比较特殊,所以考虑从上到下遍历。借用扫描线的思想,构造一颗单点覆盖区间查询的线段树。

先对数据离散化,这样只要建立一颗1-200000范围的树即可。

然后从上往下,对于一个纵座标y,我们考虑所有在这个y上出现的点的x值。我们把这些x值全部更新到线段树上,总区间和tree[1]表示到当前y为止,总共有多少个不同的x值出现。那么很显然的,ans+=(tree[1]+1)tree[1]/2ans+=(tree[1]+1)*tree[1]/2,也就是所有可能的不同选法。但是要考虑一些其他情况,对于某个区间,如果在当前y上没有新的x值产生(或者自己覆盖自己),那么这个区间其实和之前出现过的区间是一样的,所有不应该被计入答案,所有用线段树查询相邻两个本y出现的x值之间历史x值的个数,然后类似上述公式减去即可。

因为每个点只被插入一次并且产生一次区间查询,所有复杂度O(NlogN)O(NlogN)

#include<bits/stdc++.h>
using namespace std;

struct node{
	int x, y;
}a[200005];
int n;
long long ans=0;
int v[200005],top=0;

const int N=200005;
int tree[200006<<2];
//单点修改 
void modify(int x,int k){
	for(x+=N;x;x>>=1)tree[x]+=k;
}
//区间查询
int query(int l,int r){
	if(l>r)return 0;
	int ans=0;
	for(l=N+l-1,r=N+r+1;l^r^1;l>>=1,r>>=1){
		if(~l&1)ans+=tree[l^1];
		if(r&1)ans+=tree[r^1];
	}
	return ans;
} 

bool cmp1(node a,node b){
	return a.x<b.x;
}

bool cmp2(node a,node b){
	if(a.y>b.y)return 1;
	if(a.y<b.y)return 0;
	return (a.x<b.x);
}

long long fun(int x){
	long long r=x;
	r=r*(r+1)/2;
	return r;
}

int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i)scanf("%d%d",&a[i].x,&a[i].y);
	sort(a+1,a+n+1,cmp1);
	int cnt=1;
	int lst=a[1].x;
	a[1].x=1;
	for(int i=2;i<=n;++i){
		if(a[i].x==lst)a[i].x=cnt;
		else{
			lst=a[i].x;
			a[i].x=++cnt;
		}
	}
	sort(a+1,a+n+1,cmp2);
	for(int i=1;i<=n;){
		int ty=a[i].y;
		top=0;
		while(a[i].y==ty)v[top++]=a[i++].x;
		for(int j=0;j<top;++j)modify(v[j],1-query(v[j],v[j]));
		v[top++]=n+1;
		ans+=fun(tree[1]);
		for(int j=0;j<top-1;++j)ans-=fun(query(v[j]+1,v[j+1]-1));
		ans-=fun(query(1,v[0]-1));
	}
	cout<<ans<<endl;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章