Codeforces Round #582 (Div. 3)

题解 Codeforces Round #582 (Div. 3)

rank: 560 1473 → 1603 Became Expert

上expert了( •̀ ω •́ )✧

A. Chips Moving

A. Chips Moving

Div.3的A.热身小题。明白题意后,统计一下奇数和偶数的个数即可

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define lor(a,b,c) for(register int a=b;a<=c;++a)
#define ror(a,b,c) for(register int a=c;a>=b;--a)

int n,a,cnt1,cnt2;

int main(){
	#ifndef ONLINE_JUDGE
	freopen("test.in","r",stdin);
	#endif

	scanf("%d",&n);
	lor(i,1,n){
		scanf("%d",&a);
		if(a%2) cnt1++; else cnt2++;
	}
	printf("%d\n",min(cnt1,cnt2));

	return 0;
}

B. Bad Prices

B. Bad Prices

由于只有后面的数字会对前面的数字有影响,因此倒序处理,事情就会被简化很多。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define lor(a,b,c) for(register int a=b;a<=c;++a)
#define ror(a,b,c) for(register int a=c;a>=b;--a)

const int MAX=150005;

int t,n,cnt,a[MAX],top;

int main(){
	#ifndef ONLINE_JUDGE
	freopen("test.in","r",stdin);
	#endif

	scanf("%d",&t);
	while(t--){
		top=0x3f3f3f3f; cnt=0;
		scanf("%d",&n);
		lor(i,1,n) scanf("%d",&a[i]);
		ror(i,1,n){
			if(a[i]>top) cnt++;
			top=min(a[i],top);
		}
		printf("%d\n",cnt);
	}

	return 0;
}

C. Book Reading

道理都懂,但是考场上还是手推了一遍以确保正确。

number repeat number repeat
\(0\) \(0\) \(5\) \(5\rightarrow 0\)
\(1\) \(1\rightarrow2\rightarrow3\rightarrow4\rightarrow5\rightarrow6\rightarrow7\rightarrow8\rightarrow9\rightarrow0\) \(6\) \(6\rightarrow2\rightarrow8\rightarrow4\rightarrow0\)
\(2\) \(2\rightarrow4\rightarrow6\rightarrow8\rightarrow0\) \(7\) \(7\rightarrow4\rightarrow1\rightarrow8\rightarrow5\rightarrow2\rightarrow9\rightarrow6\rightarrow3\rightarrow0\)
\(3\) \(3\rightarrow6\rightarrow9\rightarrow2\rightarrow5\rightarrow8\rightarrow1\rightarrow4\rightarrow7\rightarrow0\) \(8\) \(8\rightarrow6\rightarrow4\rightarrow2\rightarrow0\)
\(4\) \(4\rightarrow8\rightarrow2\rightarrow6\rightarrow0\rightarrow\) \(9\) \(9\rightarrow8\rightarrow7\rightarrow6\rightarrow5\rightarrow4\rightarrow3\rightarrow2\rightarrow1\rightarrow0\)

由于\(n\),\(m\)都在\(10^{16}\)范围内,可用\(long\ long\)存下,因此实现起来难度可以接受ˋ( ° ▽、° )

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define lor(a,b,c) for(register int a=b;a<=c;++a)
#define ror(a,b,c) for(register int a=c;a>=b;--a)

int q; ll n,m,tot; int last;
int rev[10][15];

void init();
ll calc(ll,int);

int main(){
	#ifndef ONLINE_JUDGE
	freopen("test.in","r",stdin);
	#endif

	init();

	scanf("%d",&q);
	while(q--){
		scanf("%I64d%I64d",&n,&m);
		tot=n/m;
		last=m%10;
		printf("%I64d\n",calc(tot,last));
	}

	return 0;
}

void init(){
	lor(i,0,9){
		int rec=i;
		while(rec!=0) rev[i][++rev[i][0]]=rec,rec+=i,rec%=10;
		rev[i][++rev[i][0]]=rec;
	}
}

ll calc(ll time,int digit){
	ll ans=0;
	ll base=0; lor(i,1,rev[digit][0]) base+=rev[digit][i];
	ans+=(time/rev[digit][0])*base;
	lor(i,1,time%rev[digit][0]) ans+=rev[digit][i];
	return ans;
}

D1. Equalizing by Division (easy version)

D2. Equalizing by Division (hard version)

D1. Equalizing by Division (easy version)

D2. Equalizing by Division (hard version)

口算一下,\(\log _2\ 2\times 10^5 \approx 18\),所以实际上这\(2\times 10 ^5\)个数字再怎么折腾,最多可以砍半\(2\times 10^5\times 18 \approx 4 \times 10^6\)次,一个非常友善的范围。发现:其实把这些“除法操作”模拟一遍也完全吃得消。

问题在于:怎么模拟才能让答案更新为“前k优“。

记录一下在考场上的思路:用一个结构体记录“当前数字大小\(s\)+已经被砍半次数\(op\)".利用优先队列取s尽可能大其次op尽可能小的struct.对于队首的\(s\)不可能有更优的\(op\)去更新它,因此为s的计数器++,然后s的答案+=op。

tips: 由于题目并没有说\(s\)越大越好,因此应该让所有的struct不断更新到零,无法继续更新,中途记录优化答案。考场上因为这个点\(wa\)了一次(#`-_ゝ-)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define lor(a,b,c) for(register int a=b;a<=c;++a)
#define ror(a,b,c) for(register int a=c;a>=b;--a)

const int MAX=2e5+5;

int n,k,a;
int vis_time[MAX],vis_cnt[MAX],ans;

struct data{
	int size,op;
	bool operator < (data b) const{
		if(size==b.size) return op>b.op;
		else return size<b.size;
	}
};
priority_queue <data> line;

int main(){
	#ifndef ONLINE_JUDGE
	freopen("test.in","r",stdin);
	#endif

	scanf("%d%d",&n,&k);
	lor(i,1,n) {scanf("%d",&a); line.push((data){a,0});}

	ans=0x3f3f3f3f;
	while(!line.empty()){
		data tmp=line.top(); line.pop();
		int size=tmp.size,op=tmp.op;
		vis_time[size]++; vis_cnt[size]+=op;
		if(vis_time[size]==k){
			ans=min(ans,vis_cnt[size]);
		}
		if(!size) continue;
		else line.push((data){size/2,op+1});
	}

	printf("%d\n",ans);

	return 0;
}

E. Two Small Strings

E. Two Small Strings

这题..感觉好毒..献祭了5发wa,但还是没能考场A ╯︿╰

自己分类讨论得过于麻烦了,借用一下题解的方法:

其实总共\(12\)种组合就能解决所有的问题:

\[1.\quad (x_1\ x_2\ x_3) (x_1\ x_2\ x_3)... (x_1\ x_2\ x_3) \]

\[2.\quad (x_1\ x_1..x_1)(x_2\ x_2..x_2)(x_3\ x_3..x_3) \]

假如比赛时能把所有情况枚举一遍,人工查检一下,说不定是能改过来的(。﹏。*)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define lor(a,b,c) for(register int a=b;a<=c;++a)
#define ror(a,b,c) for(register int a=c;a>=b;--a)

int n,a[3],b[3],r[4];
string input;

int main(){
	#ifndef ONLINE_JUDGE
	freopen("test.in","r",stdin);
	#endif

	while(scanf("%d",&n)!=EOF){
	cin>>input;
	a[1]=input[0]-'a'+1; a[2]=input[1]-'a'+1;
	cin>>input;
	b[1]=input[0]-'a'+1; b[2]=input[1]-'a'+1;

	lor(i,1,3) lor(j,1,3) lor(k,1,3){
		if(i==j||i==k||j==k) continue;
		if(i==a[1]&&j==a[2]||j==a[1]&&k==a[2]||k==a[1]&&i==a[2]) continue;
		if(i==b[1]&&j==b[2]||j==b[1]&&k==b[2]||k==b[1]&&i==b[2]) continue;
		r[1]=i; r[2]=j; r[3]=k; break;
	}
	if(r[1]){
		printf("YES\n");
		lor(i,1,n) printf("%c%c%c",'a'+r[1]-1,'a'+r[2]-1,'a'+r[3]-1);
		printf("\n");
		// return 0;
	}
	
	else if(a[1]==b[1]){
		printf("YES\n");
		lor(i,1,3) if(i!=a[1]){
			lor(j,1,n) printf("%c",'a'+i-1);
		}
		lor(j,1,n) printf("%c",'a'+a[1]-1);
		printf("\n");
		// return 0;
	}

	else if(a[2]==b[2]){
		printf("YES\n");
		lor(j,1,n) printf("%c",'a'+a[2]-1);
		lor(i,1,3) if(i!=a[2]){
			lor(j,1,n) printf("%c",'a'+i-1);
		}
		printf("\n");
		// return 0;
	}

	else if(a[1]==b[2]&&a[2]==b[1]){
		printf("YES\n");
		lor(j,1,n) printf("%c",'a'+a[1]-1);
		lor(i,1,3) if(i!=a[1]&&i!=a[2]) lor(j,1,n) printf("%c",'a'+i-1);
		lor(j,1,n) printf("%c",'a'+a[2]-1);
		printf("\n");
		// return 0;
	}
	}

	return 0;
}

F. Unstable String Sort

F. Unstable String Sort

比赛后补上的。个人感觉”拓排“+”tarjan“应该是可以做的,但题解思路精奇,学习了一波。

为了满足题意,求一下”k的最大化情况“。在K最大时,字符串的两个字母能不相同就不相同,但在一些情况下,两个字母可能不得不相同。

e.p. :

3 2

1 2 3

1 3 2

例如这种情况下,s[2]和s[3]是不得不相同的,否则就没法满足题意。因此需要快速知道字符串可以被最大分成”几块“

方法:

\(1\)\(n\)枚举位置\(i\),设两个集合\(set1\)\(set2\),将\(p[i]\)加入\(set1\)中,\(q[i]\)加入\(set2\)中。当两个集合内的数字完全相同时,集合内的所有位置被分为一块中,集合清空。

尝试证明:

(一)如果P和Q中,A和B的顺序是这样的
mxWiZQ.png
那么\(A\Rightarrow^{red} B\)\(B\Rightarrow^{blue} A\)两套独立路线,因此A和B双连通

(二)否则A和B的顺序就是这样的
mx4cS1.png
根据鸽巢原理,C和D是一定存在的,由于满足情形(一),因此A和B的关系等同于C和D的关系。转化下去一定是可以”勾“到的。否则两部分相互分离,当初就不会分在一块

所以..就算证毕喽(●'◡'●)

tips:这里的\(set\)判等方法很有趣还很高效,代码如下:

set <int> s1,s2;
vector <int> vc;
lor(i,1,n){
	if(s2.count(a[i])) s2.erase(a[i]); else s1.insert(a[i]);
	if(s1.count(b[i])) s1.erase(b[i]); else s2.insert(b[i]);
	if(s1.empty()&&s2.empty()) vc.push_back(i);
}
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define lor(a,b,c) for(register int a=b;a<=c;++a)
#define ror(a,b,c) for(register int a=c;a>=b;--a)

const int MAX=2e5+5;

int n,m,a[MAX],b[MAX],out[MAX];

set <int> s1,s2;
vector <int> vc;

int main(){
	#ifndef ONLINE_JUDGE
	freopen("test.in","r",stdin);
	#endif

	scanf("%d%d",&n,&m);
	lor(i,1,n) scanf("%d",&a[i]);
	lor(i,1,n) scanf("%d",&b[i]);

	lor(i,1,n){
		if(s2.count(a[i])) s2.erase(a[i]); else s1.insert(a[i]);
		if(s1.count(b[i])) s1.erase(b[i]); else s2.insert(b[i]);
		if(s1.empty()&&s2.empty()) vc.push_back(i);
	}

	if(vc.size()<m) return printf("NO\n"),0;

	printf("YES\n");
	int l=1,r;
	lor(i,1,vc.size()){
		r=vc[i-1];
		int cur=min(i,26);
		lor(j,l,r) out[a[j]]=cur;
		l=r+1;
	}
	lor(i,1,n) printf("%c",'a'+out[i]-1);
	printf("\n");

	return 0;
}

G. Path Queries

G. Path Queries

在最后25min的时后爆发了不灭的斗志,结束前5min的第二发A了这题(/▽\)

由于是离线的,排序之后用并查集维护信息就好。

”公式“:对于大小为\(n\)的连通块,有\(\frac{n\times(n-1)}{2}\)个点对。

tips:这道题需要\(long\ long\)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define lor(a,b,c) for(register int a=b;a<=c;++a)
#define ror(a,b,c) for(register int a=c;a>=b;--a)

const int MAX=2e5+5;

int n,m;
int ecnt,edge[MAX<<1],head[MAX],nxt[MAX<<1],w[MAX<<1];
int fa[MAX],fa_size[MAX];
ll ans;

struct data{
	int id,q; ll ans;
}a[MAX];
bool cmpi(data a,data b) {return a.id<b.id;}
bool cmpq(data a,data b) {return a.q<b.q;}

struct data2{
	int u,v,wei;
}bian[MAX];
bool cmpw(data2 a,data2 b) {return a.wei<b.wei;}

inline void insert(int,int,int,int);
int find(int);
void unionn(int,int);
inline ll calc(int);

int main(){
	#ifndef ONLINE_JUDGE
	freopen("test.in","r",stdin);
	#endif

	scanf("%d%d",&n,&m);
	lor(i,1,n-1){
		int u,v,wei; scanf("%d%d%d",&u,&v,&wei);
		bian[i].u=u; bian[i].v=v; bian[i].wei=wei;
		insert(u,v,wei,++ecnt); insert(v,u,wei,++ecnt);
	}
	sort(bian+1,bian+n,cmpw);

	lor(i,1,m) {scanf("%d",&a[i].q); a[i].id=i;}
	sort(a+1,a+1+m,cmpq);

	lor(i,1,n) fa[i]=i,fa_size[i]=1;

	int pick=0;
	lor(i,1,m){
		while(pick<n-1&&bian[pick+1].wei<=a[i].q) {pick++; unionn(bian[pick].u,bian[pick].v);}
		a[i].ans=ans;
	}

	sort(a+1,a+1+m,cmpi);
	lor(i,1,m) printf("%I64d ",a[i].ans); printf("\n");

	return 0;
}

inline void insert(int from,int to,int wei,int id){
	nxt[id]=head[from]; head[from]=id; edge[id]=to; w[id]=wei;
}

int find(int u){
	if(fa[u]==u) return fa[u];
	else return fa[u]=find(fa[u]);
}

void unionn(int a,int b){
	int faa=find(a),fab=find(b);
	if(faa==fab) return;
	ans-=calc(fa_size[faa]); ans-=calc(fa_size[fab]);
	ans+=calc(fa_size[faa]+fa_size[fab]);
	fa[faa]=fab; fa_size[fab]+=fa_size[faa];
}

inline ll calc(int a) {return 1ll*a*(a-1)/2;}
posted @ 2020-06-29 22:45  ticmis  阅读(176)  评论(0编辑  收藏  举报