您的位置:首页 > 其它

Codeforces Educational Codeforces Round 42 (Rated for Div. 2) D,E,F

2018-04-11 21:08 471 查看

D

题意

每次把最小的两个给合起来,然后把右边的一个变成这个数的两倍,问最后的序列

分析

我的做法有点蠢,直接暴力合并,开一个权值线段树,叶子结点开个set存位置,然后维护同种元素最多出现多少个,一边找一边并就好

最后把所有的叶子结点给扫一遍,map一下

代码

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll inf = 1e18;
const ll N = 1234567;
inline ll read()
{
ll p=0; ll f=1; char ch=getchar();
while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
return p*f;
}

ll rt,tot,lc[N<<2],rc[N<<2]; set<ll> s[N<<2]; ll c[N<<2];
void link(ll &u,ll L,ll R,ll k,ll cc)
{
if(!u) u=++tot;
if(L==R)
{
s[u].insert(cc);
c[u] = s[u].size();
return ;
}
ll mid = (L+R)>>1;
if(k<=mid) link(lc[u],L,mid,k,cc);
else link(rc[u],mid+1,R,k,cc);
c[u] = max(c[lc[u]] , c[rc[u]]);
}

void find(ll u,ll L,ll R)
{
if(L==R)
{
s[u].erase(s[u].begin());
link(rt,1,inf,2*L,*s[u].begin());
s[u].erase(s[u].begin());
c[u] = s[u].size();
//printf("%d\n",L);
return ;
}
ll mid=(L+R)>>1;
if(c[lc[u]] >= 2) find(lc[u],L,mid);
else find(rc[u],mid+1,R);
c[u] = max(c[lc[u]] , c[rc[u]]);
}

map<ll,ll> mp;

void qry(ll u,ll L,ll R)
{
if(!u) return ;
if(L==R)
{
for(auto i : s[u]) mp[i]=L;
return ;
}
ll mid=(L+R)>>1;
qry(lc[u],L,mid);
qry(rc[u],mid+1,R);
}

ll ans
;

int main()
{

ll n = read(); rt=tot=0;
for(ll i=1;i<=n;i++)
{
ll x=read();
link(rt,1,inf,x,i);
}

while(1)
{
if(c[1] <= 1) break;
find(rt,1,inf);
}

qry(rt,1,inf);

printf("%d\n",mp.size());
for(auto i:mp) printf("%lld ",i.second);

return 0;
}


E

题意

在坐标轴上有很多个点,R,B,P,然后你要把这些点给连边,代价为坐标的绝对值的差, 然后使得这个图去掉R点后B和P都仍然全部联通或者去掉B点后R和P仍然全部都联通

分析

考虑P点之间的情况,要不就是P点之间连两条链,要不就是首先两个P点先连,然后对于R的点连向P点的情况就是分成两边,一边连前面的端点,一边连后面的端点,对于B也这样贪心,肯定有两个决策点,看看是连两条链优还是断开优

代码

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll N = 1000010;
inline ll read()
{
ll p=0; ll f=1; char ch=getchar();
while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
return p*f;
}
ll col
,a
; ll n; ll p
,plen = 0;
int main()
{

n=read();
for(ll i=1;i<=n;i++)
{
ll x = read(); char ch; scanf("\n%c",&ch);
if(ch=='R') col[i] = 1; else if(ch=='B') col[i] = 2; else col[i] = 3;
a[i] = x;
}

ll s=0,d=n+1;
for(ll i=1;i<=n;i++) if(col[i] == 3){s=i; break;}
for(ll i=n;i>=1;i--) if(col[i] == 3){d=i; break;}
if(s==0)
{
ll lst = 0; ll ans = 0;
for(ll i=1;i<=n;i++)
{
if(col[i] == 2) continue;
if(lst) ans+=a[i] - a[lst];
lst = i;
}
lst = 0;
for(ll i=1;i<=n;i++)
{
if(col[i] == 1) continue;
if(lst) ans+=a[i] - a[lst];
lst = i;
}printf("%lld\n",ans);
return 0;
}

ll lst = 0; ll ans = 0;
for(ll i=1;i<=s;i++)
{
if(col[i] == 2) continue;
if(lst) ans+=a[i] - a[lst];
lst = i;
}
lst = 0;
for(ll i=1;i<=s;i++)
{
if(col[i] == 1) continue;
if(lst) ans+=a[i] - a[lst];
lst = i;
}

lst = d;
for(ll i=d+1;i<=n;i++)
{
if(col[i] == 2) continue;
if(lst) ans+=a[i] - a[lst];
lst = i;
}

lst = d;
for(ll i=d+1;i<=n;i++)
{
if(col[i] == 1) continue;
if(lst) ans+=a[i] - a[lst];
lst = i;
}

ll nx = 0;
for(ll i=s;i<d;i=nx)
{
ll ss = 0;
nx = i+1; while(col[nx] !=3) nx++;

plen = 0;
for(ll j=i+1;j<nx;j++)
{
if(col[j] == 1) p[++plen] = j;
}

ll minx = LLONG_MAX;
for(ll j=0;j<=plen;j++)
{
ll o = 0; if(j) o += a[p[j]] - a[i]; if(j+1<=plen) o += a[nx] - a[p[j+1]];
minx = min(minx , o);
}ss+=minx;

plen = 0;
for(ll j=i+1;j<nx;j++)
{
if(col[j] == 2) p[++plen] = j;
}

minx = LLONG_MAX;
for(ll j=0;j<=plen;j++)
{
ll o = 0; if(j) o += a[p[j]] - a[i]; if(j+1<=plen) o += a[nx] - a[p[j+1]];
minx = min(minx , o);
}ss+=minx;

ss += a[nx] - a[i];
ss = min(ss , 2 * (a[nx] - a[i]));

// printf("%lld\n",ss);
ans += ss;
}

return printf("%lld\n",ans),0;
}


F

题意

问哪些边在简单环上

分析

简单环就是一个点联通分量,点数和边数相同,一条边找到dfs序比较大的点,也就是深度比较大的点,这条边属于的联通分量就是这条边属于的联通分量

(因为可能一个点属于多个联通分量)

代码

#include <bits/stdc++.h>
#define pb push_back
using namespace std;
const int N = 1234567;
inline int read()
{
int p=0; int f=1; char ch=g
ca06
etchar();
while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
return p*f;
}
struct node{int x,y,next;}edge
; int len,first
;
void ins(int x,int y){len++; edge[len].x=x; edge[len].y=y; edge[len].next=first[x]; first[x]=len;}
int dfn
,low
,id=0,cnt=0; stack<int> s; int n,m;
vector<int> scc
; int bel
;
void dfs(int x)
{
dfn[x] = low[x] = ++id; s.push(x);
for(int k=first[x];k!=-1;k=edge[k].next)
{
int y = edge[k].y;
if(dfn[y]==-1)
{
dfs(y); low[x] = min(low[x] , low[y]);
if(low[y] >= dfn[x])
{
cnt++; scc[cnt].pb(x); int i;
do
{
i = s.top();
scc[cnt].pb(i); bel[i] = cnt; s.pop();
}while(i!=y);
}
}
else low[x] = min(low[x],dfn[y]);

}
}

vector<int> siz
;
vector<int>v;
int main()
{
len = 1; memset(first,-1,sizeof(first));
n = read(); m = read();
for(int i=1;i<=m;i++)
{
int x = read(); int y = read();
ins(x,y); ins(y,x);
}
memset(dfn,-1,sizeof(dfn));
memset(low,-1,sizeof(low));
//dfs(3);
cnt = 0; for(int i=1;i<=n;i++) if(dfn[i] == -1){while(!s.empty()) s.pop();
dfs(i);}

for(int i=2;i<=len;i+=2)
{
int p = dfn[edge[i].x] > dfn[edge[i].y] ? edge[i].x : edge[i].y;
siz[bel[p]].pb(i/2);
}

for(int i=1;i<=cnt;i++)
{
if(scc[i].size() == siz[i].size()) for(auto j:siz[i]) v.pb(j);
}

printf("%d\n",v.size()); sort(v.begin(),v.end());
for(int i=0;i<v.size();i++) printf("%d%c",v[i]," \n"[i==v.size()-1]);

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐