Codeforces Round #826 (Div. 3)
Codeforces Round #826 (Div. 3)
E. Sending a Sequence Over the Network
题目大意
假设一个数组a=[1,2,3,4,5],将其分割为,[1],[2,3],[4,5,6],以此构建一个新数组,构建的原则是,分割的各部分的长度需要在该段的左边或右边,例如分割为b = [1,1,2,2,3,3,4,5,6]。
给定一个数组b,求是否有合法的a。
分析
是一道不难的DP,写的时候nt了,写了好久。
我们来简单说一下思路。我们用dp[i]来表示第i个点结尾可以得到合法解。
我们考虑每个数字,如果将其作为表示某个段的长度,则其覆盖的要不是前边的,要不是后面。
则我们考虑如果覆盖前边,则若dp[i-a[i]-1]是合法的,则当前点一定合法。
然后去看如果当前点覆盖后边,去更新后面的点为dp[i+a[i]+1]。
结束啦。
AC_code
#include <bits/stdc++.h>
#define fi first
#define se second
#define endl '\n'
#define ios ios::sync_with_stdio(false); cin.tie(0), cout.tie(0)
using ll = long long;
using namespace std;
const int N = 1e5 + 10,M = N*2;
void solve() {
int n;cin>>n;
vector<int> b(n);
vector<int> f(n+1);
for(auto &x:b) cin>>x;
f[0] = 1;
for(int i=0;i<=n;i++)
{
if(i&&i-1-b[i-1]>=0) f[i] |= f[i-1-b[i-1]];
if(i<n&&i+b[i]+1<=n) f[i+b[i]+1] |= f[i];
}
if(f[n]) cout<<"YES\n";
else cout<<"NO\n";
}
int main()
{
ios;
int T=1;
cin>>T;
while(T -- ) {
solve();
}
return 0;
}
F. Multi-Colored Segments
题目大意
给定一些线段,其中每个线段有一个颜色,问每一个线段距离其最近的不同颜色的线段的距离。
分析
倒也不难,不过有一些麻烦。
我们来看看。
我们首先来看看不考虑颜色
我们建立权值线段树,接下来对于每个线段,是否有别的线段与其相交,若有则为0。
若无,我们用multisetL,R存起来所有的左端点和右端点。直接寻找除该线段外的最近的其他线段。
具体的就是,对于该线段的左端点,在R中寻找最近的右端点,对于该线段的右端点,在L中寻找最近的左端点。
有颜色
也很简单,我们直接对于每种颜色单独操作,当遍历该颜色的线段时,将所有的该颜色的线段影响全部消除。
小细节
我们可以看到权值很大,因此我们直接建立动态开点线段树。当然也可以进行离散化后的线段树,当然也可以离散化后的树状数组。
我是为了练习,写的动态开点线段树,赛时当然选择离散化后的树状数组,会好写很多。
AC_code
#include<bits/stdc++.h>
#define ios ios::sync_with_stdio(false); cin.tie(0), cout.tie(0)
using namespace std;
const int N = 2e5 + 10,inf = 0x3f3f3f3f;
struct Seg
{
int l,r,c,id;
}segs[N];
vector<int> col[N];
struct Node
{
int l,r;
int sum,add;
}tr[N<<6];
int n,idx,root,ans[N];
void pushup(int u)
{
tr[u].sum = tr[tr[u].l].sum + tr[tr[u].r].sum;
}
void pushdown(int u,int l,int r)
{
if(!tr[u].l) tr[u].l = ++idx;
if(!tr[u].r) tr[u].r = ++idx;
auto &root = tr[u],&left = tr[tr[u].l],&right = tr[tr[u].r];
int mid = l + r >> 1;
if(root.add)
{
left.add += root.add;
right.add += root.add;
left.sum += (mid - l + 1)*root.add;
right.sum += (r - mid)*root.add;
root.add = 0;
}
}
void modify(int &u, int l, int r, int x, int y, int v) {
if(!u) u = ++ idx;
if(x <= l && y >= r) {
int len = r - l + 1;
tr[u].sum += len * v;
tr[u].add += v;
return ;
}
pushdown(u, l, r);
int mid = l + r >> 1;
if(x <= mid) modify(tr[u].l, l, mid, x, y, v);
if(y > mid) modify(tr[u].r, mid + 1, r, x, y, v);
pushup(u);
}
int query(int u,int l,int r,int L,int R)
{
if(R<l||L>r) return 0;
if(!u) return 0;
if(L<=l&&r<=R) return tr[u].sum;
pushdown(u,l,r);
int mid = l + r >> 1;
return query(tr[u].l,l,mid,L,R) + query(tr[u].r,mid+1,r,L,R);
}
void solve()
{
cin>>n;
multiset<int> L,R;
for(int i=1;i<=n;i++) col[i].clear();
for(int i=1;i<=idx;i++) tr[i].l = tr[i].r = tr[i].sum = tr[i].add = 0;
root = idx = 0;
for(int i=1;i<=n;i++)
{
auto &[l,r,c,id] = segs[i];
cin>>l>>r>>c;
id = i;ans[i] = inf;
col[c].push_back(i);
L.insert(l),R.insert(r);
modify(root,1,inf,l,r,1);
}
for(int i=1;i<=n;i++)
{
for(auto it:col[i])
{
auto &[l,r,c,id] = segs[it];
L.erase(L.lower_bound(l));
R.erase(R.lower_bound(r));
modify(root,1,inf,l,r,-1);
// cout<<query(root,1,inf,l,r)<<" "<<l<<" "<<r<<endl;
}
for(auto it:col[i])
{
auto &[l,r,c,id] = segs[it];
int res = query(1,1,inf,l,r);
// cout<<l<<" "<<r<<" "<<c<<" "<<id<<" ";
// cout<<res<<endl;
if(res)
{
ans[id] = 0;
continue;
}
auto it1 = L.lower_bound(r),it2 = R.lower_bound(l);
if(it1 != L.end())
{
ans[id] = min(ans[id],max(0,*it1-r));
// cout<<ans[id]<<' '<<id<<endl;
}
if(it2 != R.begin())
{
ans[id] = min(ans[id],max(0,l - *--it2));
// cout<<ans[id]<<' '<<id<<endl;
}
}
for(auto it:col[i])
{
auto &[l,r,c,id] = segs[it];
L.insert(l);R.insert(r);
modify(root,1,inf,l,r,1);
}
}
for(int i=1;i<=n;i++) cout<<(ans[i]==inf?0:ans[i])<<' ';
cout<<'\n';
}
int main()
{
ios;
int T;cin>>T;
while(T--) solve();
return 0;
}

浙公网安备 33010602011771号