Codeforces Round 884

链接

C. Particles

题解

考虑把所有删除的数字标出,除首尾外,这些数字构成若干个长度为奇数的区间,且任意两个区间恰好有一个数字没有被删除。

就是奇偶分组后每组正数之和的较大值。

D. Row

题解

构造题,等价于构造一个字符集最小的字符串,使得任意相同字符之间距离不是整个串长的因数。

考虑最小的合法距离是串长的最小的不是因数的数 \(k\),答案一定不会小于 \(k\)。并且显然这个数的任意整数倍也一定不是因数,所以直接构造 \(12\cdots k12\cdots k\) 即可。

E. Great Grids

题解

场上有一个奇特的想法。

不妨令 \(A,B,C\) 分别为 \(\bmod 3\) 意义下的 \(0,1,2\)。考虑在网格图上连边:对于竖着的边,如果下面的点是上面 \(+1\),那么连边;对于横着的边,如果右边的点是左边 \(-1\),那么连边。

例如:

0 1   1-0   0-2   1 2
| |         | |      
1 2   0-2   1-0   0 1

容易发现,无论什么情况中,每一行和每一列的连边情况都是相同的。

那么,如果左下等于右上,那么行连边和列连边情况相反。如果左上等于右下,那么连边情况相同。

容易证明,只要构造出连边情况,就能构造出一组合法解。用正反集判断即可。

代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int N=20010;
int n,m,f[N],tt;
int find(int x){return f[x]==x?f[x]:(f[x]=find(f[x]));}
void link(int x,int y){f[find(x)]=find(y),f[find(x+tt)]=find(y+tt);}
void cut(int x,int y){f[find(x+tt)]=find(y),f[find(x)]=find(y+tt);}
int main()
{
    int T;scanf("%d",&T);
    while(T --> 0)
    {
        int k;scanf("%d%d%d",&n,&m,&k);
        tt=n+m-2;
        for(int i=1;i<=tt*2;i++) f[i]=i;
        for(int i=1;i<=k;i++)
        {
            int x1,y1,x2,y2;scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            if(y2==y1+1) link(x1,y1+n-1);
            else cut(x1,y2+n-1);
        }
        bool hv=true;
        for(int i=1;i<=tt;i++) if(find(i)==find(i+tt)){hv=false;break;}
        puts(hv?"YES":"NO");
    }
    return 0;
}

F. Min Cost Permutation

题解

首先考虑 Easy Version。容易证明,当 \(c\geq 0\) 时,顺序时取到最小值且此时一定字典序最小。当 \(c<0\) 时,逆序时取到最小值,但此时不一定是答案。

\(c<0\) 时,考虑用调整法,从前往后贪心。容易证明,无论前面取什么值,剩下位置按逆序排列一定取最小值。可以在 \(O(1)\) 时间内判断是否取到最小值。可以做到复杂度 \(O(n^2)\)

考虑 Hard Version。先排个顺序,不妨假设现在要确定第 \(x\) 个位置,可以证明,\(y\) 可以成为合法答案当且仅当 \(a_{y+1}-a_{y-1}\leq c\) 并且 \(|a_{y-1}-a_x|\leq c\) 或者 \(x=y\)

用链表维护 \(a\) 序列并用 set 维护满足 \(a_{y+1}-a_{y-1}\leq c\) 的集合,从中找出满足 \(|a_{y-1}-a_x|\leq c\) 最小的即可。复杂度 \(O(n\log n)\)

代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#include<set>
#define fi first
#define se second
using namespace std;
const int N=200010;
int a[N],res[N],c;
typedef long long ll;
int F(int x,int y){return abs(x-y-c);}
int L[N],R[N];
set<pair<int,int>>st;
void del(int x){R[L[x]]=R[x];L[R[x]]=L[x];}
bool check(int x){return L[x] && R[x] && a[R[x]]-a[L[x]]<=-c;}
void upd(int x,bool op)
{
    if(!x) return;
    if(op && !st.count({a[x],x})) st.insert({a[x],x});
    if(!op && st.count({a[x],x})) st.erase({a[x],x});
}
void solve()
{
    int n;
    scanf("%d%d",&n,&c);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    sort(a+1,a+n+1);
    if(c>=0){for(int i=1;i<=n;i++) printf("%d ",a[i]);puts("");return;}
    for(int i=1;i<=n;i++) L[i]=i-1,R[i]=i+1;R[n]=0;
    R[0]=1,L[0]=n;
    for(int i=1;i<=n;i++) if(check(i)) st.insert({a[i],i});
    for(int t=1;t<=n;t++)
    {
        int i=0;
        if(t==1) i=n;
        else
        {
            auto it=st.lower_bound({res[t-1]+c,0});
            if(it==st.end()) i=L[0];
            else i=it->se;
            st.erase({a[i],i});
        }
        res[t]=a[i],del(i);
        upd(R[i],check(R[i])),upd(L[i],check(L[i]));
        if(t!=n) upd(L[0],true);
    }
    for(int i=1;i<=n;i++) printf("%d ",res[i]);puts("");
}
int main()
{
    int T;scanf("%d",&T);
    while(T --> 0) solve();
    return 0;
}

G. Tree Weights

题解

很妙的题。

容易发现,实际上就是要解出每个点的深度 \(f_i\),使得 \(f_i+f_{i+1}-2f_{lca}=d_i\),并且 \(f_1=0\)

不妨考虑简单的情况。注意到 \(f_{lca}\) 前有一个系数 \(2\),如果只需要求出深度对 \(2\) 取模的结果,那么可以直接从 \(f_i\) 推出 \(f_{i+1}\)

类比牛顿迭代。假设已经知道关于 \(2^{x-1}\) 取模的答案 \(f_i'\),那么关于 \(2^x\) 取模的答案 \(f_i\) 满足 \(f_i+f_{i+1}-2f_{lca}'\equiv d_i\pmod{2^x}\)

总复杂度 \(O(n\log n)\)

代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int N=100010;
typedef long long ll;
int nxt[N<<1],to[N<<1],head[N],cnt;
void add(int u,int v){nxt[++cnt]=head[u],to[cnt]=v,head[u]=cnt;}
int f[N][20],dep[N],_2[N],g[N],x[N],y[N];
ll res[N],tmp[N],d[N];
void dfs(int u,int p)
{
    f[u][0]=p,dep[u]=dep[p]+1;
    for(int i=1;f[u][i-1];i++) f[u][i]=f[f[u][i-1]][i-1];
    for(int i=head[u];i;i=nxt[i]) if(to[i]!=p) dfs(to[i],u);
}
int lca(int u,int v)
{
    if(dep[u]<dep[v]) swap(u,v);
    for(int i=_2[dep[u]-dep[v]];i>=0;i--) if(dep[f[u][i]]>=dep[v]) u=f[u][i];
    if(u==v) return u;
    for(int i=_2[dep[u]];i>=0;i--) if(f[u][i]!=f[v][i]) u=f[u][i],v=f[v][i];
    return f[u][0];
}
int main()
{
    int n;scanf("%d",&n);
    for(int i=1;i<=n;i++) _2[i]=_2[i>>1]+1;
    for(int i=1;i<n;i++) scanf("%d%d",&x[i],&y[i]),add(x[i],y[i]),add(y[i],x[i]);
    for(int i=1;i<n;i++) scanf("%lld",&d[i]);
    dfs(1,0);
    for(int i=1;i<n;i++) g[i]=lca(i,i+1);
    for(int p=0;p<=60;p++)
    {
        ll m=1ll<<p;
        for(int i=1;i<=n;i++) tmp[i]=res[i];
        for(int i=1;i<n;i++) res[i+1]=((tmp[g[i]]*2%m-res[i]+d[i])%m+m)%m;
    }
    for(int i=1;i<n;i++) if(res[i]+res[i+1]-res[g[i]]*2!=d[i]){puts("-1");return 0;}
    for(int i=1;i<n;i++) if((dep[x[i]]<dep[y[i]])!=(res[x[i]]<res[y[i]]) || res[x[i]]==res[y[i]]){puts("-1");return 0;}
    for(int i=1;i<n;i++) printf("%lld\n",abs(res[x[i]]-res[y[i]]));
    return 0;
}

H. Multiple of Three Cycles

咕咕咕。

posted @ 2023-07-19 22:32  Flying2018  阅读(5)  评论(0编辑  收藏  举报