Codeforces Round #582 (Div. 3)
作者:互联网
题解 Codeforces Round #582 (Div. 3)
rank: 560 1473 → 1603 Became Expert
上expert了( •̀ ω •́ )✧
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
由于只有后面的数字会对前面的数字有影响,因此倒序处理,事情就会被简化很多。
#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
这题..感觉好毒..献祭了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
比赛后补上的。个人感觉”拓排“+”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的顺序是这样的
那么\(A\Rightarrow^{red} B\)和\(B\Rightarrow^{blue} A\)两套独立路线,因此A和B双连通(二)否则A和B的顺序就是这样的
根据鸽巢原理,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
在最后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;}
标签:582,int,ll,Codeforces,long,lor,printf,Div,scanf 来源: https://www.cnblogs.com/ticmis/p/13210879.html