Codeforces Round #686 (Div. 3)
A. 给出一个错排。
题解:整体左移一位即可。
#include<bits/stdc++.h>
using namespace std;
int main(){
int _;cin>>_;
while(_--){
int n;cin>>n;
for(int i=1;i<n;++i)cout<<i+1<<" ";
cout<<1<<endl;
}
return 0;
}
B. 找一个尽量小的出现一次的数字角标。
题解:记录一下角标,从小往大贪心。
#include<bits/stdc++.h>
using namespace std;
map<int,int>H;
map<int,int>idx;
int main(){
int _;cin>>_;
while(_--){
H.clear();
idx.clear();
int n;cin>>n;
for(int i=1;i<=n;++i){
int x;cin>>x;
++H[x];
idx[x]=i;
}
int flag=0;
for(auto& p:H){
if(p.second==1){
cout<<idx[p.first]<<endl;
flag=1;
break;
}
}
if(!flag){
cout<<"-1"<<endl;
}
}
return 0;
}
C. 给你n个数的数组,你需要选定一个数,这个数不能碰,选择包含其他数的段进行删除。问最少删除几次能使得整个数组只剩下这个数字?
题解:枚举数字,每次暴力往下一个跳就好了。
#include<bits/stdc++.h>
using namespace std;
const int N = 200005;
int n, a[N], vis[N], Next[N], last[N];
int main(){
int _;cin>>_;
while(_--){
cin>>n;
for(int i=1;i<=n+1;++i){
vis[i]=Next[i]=last[i]=-1;
}
for(int i=1;i<=n;++i)cin>>a[i];
for(int i=n;i>=1;--i){
Next[i]=last[a[i]];
last[a[i]]=i;
}
int ans=n;
for(int i=1;i<=n;++i){
if(vis[i]==-1){
vis[i]=1;
int t=(i==1)?0:1;
int cur=i, nxt=Next[i];
int flag=cur;
while(nxt!=-1){
flag=max(flag,nxt);
vis[nxt]=1;
if(nxt!=cur+1)++t;
cur=nxt;
nxt=Next[nxt];
}
if(flag!=n)++t;
ans=min(ans,t);
}
}
cout<<ans<<endl;
}
return 0;
}
D. 给你一个数,你要拆成多个数之积,并且每一个数都是后面一个数的因子。
题解:质因数分解之后,最优构造取决于最大幂次。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 100005;
bool isNot[N];
int prime[N], tol;
void sieve(){
for(int i=2;i<=100000;++i){
if(!isNot[i]){
prime[++tol]=i;
for(int j=2*i;j<=100000;j+=i){
isNot[j]=1;
}
}
}
}
int main(){
sieve();
int _;cin>>_;
while(_--){
LL n;cin>>n;
int mx=1;
LL id=-1;
for(int i=1;i<=tol;++i){
if(1ll*prime[i]*prime[i]>n)break;
int cnt=0;
LL t=n;
while(t%prime[i]==0){
++cnt;
t/=prime[i];
}
if(cnt>mx){
mx=cnt;
id=prime[i];
}
}
if(mx==1){
cout<<"1"<<endl;
cout<<n<<endl;
}else{
cout<<mx<<endl;
for(int i=1;i<mx;++i){
cout<<id<<" ";
n/=id;
}
cout<<n<<endl;
}
}
return 0;
}
E. 给你n个点的基环树,问你简单路径的条数。
题解:首先考虑只有环的情况,结果显然是n*(n-1)。考虑一颗树上,每一个点,到本树另一个点的简单路径只有一条。所以,我们要考虑所有树的尺寸就好了。关于这个,我们可以在无向图拓扑排序的时候,用一个DSU维护每棵树的尺寸。
#include<bits/stdc++.h>
using namespace std;
const int N = 200005;
typedef long long LL;
int n, deg[N], f[N], vis[N], sz[N];
vector<int> G[N];
inline int Find(int x){return x==f[x]?x:f[x]=Find(f[x]);}
int main(){
int _;scanf("%d",&_);
while(_--){
scanf("%d",&n);
for(int i=1;i<=n;++i){
G[i].clear();
deg[i]=0;
f[i]=i;
vis[i]=0;
sz[i]=1;
}
for(int i=1;i<=n;++i){
int u, v;
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
++deg[u];
++deg[v];
}
LL ans=1ll*n*(n-1);
queue<int> q;
for(int i=1;i<=n;++i){
if(deg[i]==1){
q.push(i);
vis[i]=1;
}
}
while(!q.empty()){
int u=q.front();
q.pop();
for(auto& v:G[u]){
if(vis[v])continue;
int fu=Find(u);
int fv=Find(v);
if(f[fu]!=f[fv]){
sz[fu]+=sz[fv];
f[fv]=fu;
}
if(--deg[v]==1){
vis[v]=1;
q.push(v);
}
}
}
for(int i=1;i<=n;++i){
if(i==f[i]&&sz[i]>1){
ans-=1ll*sz[i]*(sz[i]-1)/2;
}
}
cout<<ans<<endl;
}
return 0;
}
F. 给你n个数的数组,你现在要切这个数组为3段。第一段最大值等于第二段最小值,等于第三段最大值。
题解:(来自I-wen Huang)。我们考虑这个相等的值,并且从大到小开始考虑。如果最大值超过3个,那直接白给。否则我们从大到小开始考虑的时候,记录一个边界(这里指大于这个值的最左和最右的边界,原因在于,在这个边界里面最大值肯定不是我们当前考虑的这个值)。这个时候,我们需要数出在这个边界中的,当前考虑的这个值的个数,且我们需要记录这个边界里,大于当前值的个数。如果大于等于这个值的个数,小于区间长度,那肯定不合法(最小值不是当前数)。这个时候,一个前缀和一个后缀都是小于等于当前值的。我们只需要考虑,三个等号是不是都可以取到就可以了。
#include<bits/stdC++.h>
using namespace std;
const int N = 200005;
int a[N], n;
map<int, vector<int>> pos;
int main(){
int _;scanf("%d",&_);
while(_--){
pos.clear();
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%d",a+i);
pos[-a[i]].push_back(i);
}
int l=n+1, r=0;
int flag=0;
int gtr=0;
for(auto& p:pos){
int x=-p.first;
vector<int> vec=p.second;
if(l>n){
int sz=(int)vec.size();
if(sz>=3){
flag=1;
cout<<"YES"<<endl;
cout<<vec[1]-1<<" 1 "<<n-vec[1]<<endl;
break;
}
}else{
int eql=0;
for(auto& v:vec){
if(v>=l&&v<=r){
++eql;
}
}
if(r-l+1<=(gtr+eql)){
if(eql>0){
if(vec[0]<l&&vec.back()>r){
flag=1;
cout<<"YES"<<endl;
cout<<l-1<<" "<<r-l+1<<" "<<n-r<<endl;
break;
}
}else{
if(l-1>1&&a[l-1]==x&&vec[0]<l-1&&vec.back()>r){
flag=1;
cout<<"YES"<<endl;
cout<<l-2<<" "<<r-l+2<<" "<<n-r<<endl;
break;
}
if(r+1<n&&a[r+1]==x&&vec[0]<l&&vec.back()>r+1){
flag=1;
cout<<"YES"<<endl;
cout<<l-1<<" "<<r-l+2<<" "<<n-r-1<<endl;
break;
}
}
}
}
for(auto& v:vec){
l=min(l,v);
r=max(r,v);
}
gtr+=(int)vec.size();
}
if(!flag){
cout<<"NO"<<endl;
}
}
return 0;
}