Silverwolfnya

ucup训练记录

DAY1

赛时切了三题,赛后补的B.

A

给定一个序列,每次询问\([l_1,r_1]\)\([l_2,r_2]\)的是否同构,题面中对同构的定义是前缀最大值出现的位置在子数组的相对位置是相等的。

考虑处理出每个数左边的第一个比之大的数的位置,记作\(L_i\),对于每次区间\([l,r]\)的询问,这里出现前缀最大值的所有位置都满足\(l+1\leq j\leq r\land L_j<l\),假设一开始所有位置都是合法的,当你倒序枚举\(l\)时,会将\(L_j \geq l\)的位置删除贡献,因此可以倒着做扫描线,并将位置看成二进制下的数位,哈希进行匹配,即第\(i\)个位置当其有贡献时要记作\(2^i\),最后匹配的时候再额外地右移\(l\)位即可。

综上,我们可以得到\(O((n+q)\log n)\)的做法。

(翻了翻别人的代码,感觉扫描线解很少啊)

#include<bits/stdc++.h>
#define fi first 
#define se second
#define pb push_back
#define mt make_tuple
using ll=long long;
using namespace std;
typedef  tuple<int,int,int>ti3;
typedef     pair<int,int>pii;
const int N=3e5+9;
//扫描线 + 哈希
const ll mod=1e15+37;
using i128=__int128;
i128 pw2[N];
i128 invpw2[N];

i128 qpow(i128 x,i128 y){
    i128 res=1;
    while(y){
        if(y&1)res=res*x%mod;
        x=x*x%mod;
        y>>=1;
    }
    return res;
}
i128 inv(i128 x){
    return qpow(x,mod-2);
}
void init(){
    pw2[0]=1;
    for(int i=1;i<N;i++)pw2[i]=pw2[i-1]*2ll%mod;
}
i128 mo(i128 x){
    return (x%mod+mod)%mod;
}
class Bit{
#define lowbit(x) x&-x
public:
    vector<i128>c;
    int n;
    Bit(int n):n(n){
        c.assign(n+1,0);
    }
    i128 Sum(int x){
        i128 sum=0;
        for(int i=x;i>0;i-=lowbit(i)){
            sum=(sum+c[i])%mod;
        }
        return sum;
    }
    i128 cal(int x,int y){
        return mo(Sum(y)-Sum(x-1));
    }
    void add(int x,i128 y){
        for(int i=x;i<=n;i+=lowbit(i))c[i]=(c[i]+y)%mod;
    }
    #undef lowbit
};
void Silverwolf(){
    int n,q;
    cin>>n>>q;
    vector<int>a(n+1),L(n+1,0);
    for(int i=1;i<=n;i++)cin>>a[i];
    vector<int>stk;//维护单调递减栈?
    for(int i=n;i>=1;i--){
        while(stk.size()&&a[i]>a[stk.back()]){
            L[stk.back()]=i;
            stk.pop_back();
        }
        stk.pb(i);
    
    }
    // for(int i=1;i<=n;i++)cout<<L[i]<<" ";cout<<'\n';
    vector<vector<int>>del(n+1);//需要删除的贡献的位置
    for(int i=1;i<=n;i++)del[L[i]].pb(i);
    //找到左边第一个比它大的位置
    vector<vector<ti3>>qry(n+1);//l:[r,j,0/1] //扫描线
    vector<vector<ll>>ask(q+1,vector<ll>(2,0)); //这里是离线的询问吧
    for(int i=1;i<=q;i++){
        int l,r;
        cin>>l>>r;
        qry[l].pb(mt(r,i,0));
        cin>>l>>r;
        qry[l].pb(mt(r,i,1));
    }
    Bit bit(n);
    for(int i=1;i<=n;i++)bit.add(i,pw2[i]);
    for(int l=n;l>=1;l--){
        for(auto j:del[l]){
            bit.add(j,-pw2[j]);
        }
        for(auto [r,j,id]:qry[l]){
            i128 tmp=0;
            if(l<r)tmp=bit.cal(l+1,r);
            tmp=tmp*inv(pw2[l-1])%mod;
            ask[j][id]=tmp;
        }
    }
    for(int i=1;i<=q;i++){
        if(ask[i][0]==ask[i][1])cout<<"Yes\n";
        else cout<<"No\n";
    }
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    init();
    // int T;cin>>T;while(T--)
    Silverwolf();
    return 0;
}
/*
10 6
3 1 4 1 5 9 2 6 5 3
1 3 3 5
1 5 6 10
1 1 9 9
1 9 1 9
1 3 6 8
5 8 7 10
0 1 0 3 0 0 6 6 8 9 


10 1
3 1 4 1 5 9 2 6 5 3
5 8 7 10
*/

B

对于一个括号序列,合法的一个必要条件是:对于前\(2i-1\)个位置,至少要有\(i\)个左括号。

那么对于\(n\)个括号序列,一定要求前\(2i-1\)个位置,左括号的数量至少是\(i\times n\)个。

这个必要条件保证了,构造这\(n\)个括号不会出现前面某个位置右括号比左括号多的情况,再加上\(\sum a_i=k\times n\)即为答案。

时间复杂度\(O(n)\)

#include<bits/stdc++.h>
#define int long long 
#define fi first 
#define se second
#define pb push_back
using ll=long long;
using namespace std;
const int N=1e6+10;



void Silverwolf(){
    ll n;
    int k;
    cin>>n>>k;
    ll cnt=0,sum=0;
    vector<ll>a(2*k+1,0),pre(2*k+1,0);
    for(int i=1;i<=2*k;i++)cin>>a[i],sum+=a[i],pre[i]=pre[i-1]+a[i];
    if(sum!=n*k)return cout<<"No\n",void();
    for(int i=1;i<2*k;i+=2){
        if(pre[i]<n*(i+1)/2)return cout<<"No\n",void();
    }
    cout<<"Yes\n";

}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int T;cin>>T;while(T--)
    Silverwolf();
    return 0;
}
/*
2
3 3
3 2 2 0 2 0
3 3
3 0 2 3 1 0


10
3 3
3 3 1 1 1 0 
3 3
3 2 2 2 0 0 
3 3
3 2 2 1 1 0 
3 3
3 2 1 2 1 0 
3 3
3 2 2 1 1 0 
3 3
3 2 2 0 2 0
3 3
3 2 1 1 2 0
3 3
3 1 3 1 1 0
3 3
3 1 2 2 1 0
3 3
3 1 2 1 2 0

2
3 3
3 2 0 2 2 0
3 3
3 2 0 3 1 0


3 3
3 2 0 2 2 0

a_i-(n-a_i)

3 1 -3....

*/

M

合法的树一定是最小生成树。

构造出最小生成树,枚举非树边,看看是否都满足\(w\geq dis_{u,v}\)即可。

时间复杂度\(O(m\log n)\)

#include<bits/stdc++.h>
#define fi first 
#define se second
#define pb push_back
using ll=long long;
using namespace std;
const int N=1e6+10;
typedef pair<int,int>pii;
class Tree{
public:
    vector<int>dep;
    vector<vector<int>>fa;
    vector<vector<pii>>e;
    vector<ll>dp;
    Tree(int n){
        dep.assign(n+1,0);
        e.resize(n+1);
        fa.assign(n+1,vector<int>(20,0));
        dp.assign(n+1,0);
    }
    void dfs(int u,int f){
        dep[u]=dep[f]+1;
        fa[u][0]=f;
        
        for(int i=1;i<=19;i++){
            fa[u][i]=fa[fa[u][i-1]][i-1];
        }
        for(auto [v,w]:e[u]){
            if(v!=f){
                dp[v]=w;
                dfs(v,u);
            }
        }
    }

    void dfs2(int u,int f){
        for(auto [v,w]:e[u]){
            if(v==f)continue;
            dp[v]+=dp[u];
            dfs2(v,u);
            
        }
    }
    void work(){
        dfs(1,0);
        dfs2(1,0);
    }
    void add(int u,int v,int w){
        e[u].pb({v,w});
        e[v].pb({u,w});
    }
    int lca(int u,int v){
        if(dep[u]<dep[v])swap(u,v);
        for(int i=19;i>=0;i--){
            if(dep[fa[u][i]]>=dep[v])u=fa[u][i];
            if(u==v)return v;

        }
        for(int i=19;i>=0;i--){
            if(fa[u][i]!=fa[v][i]){
                u=fa[u][i],v=fa[v][i];
            }
        }
        return fa[u][0];
    }
    ll dis(int u,int v){
        return dp[u]+dp[v]-2*dp[lca(u,v)];
    }
};
struct edge{
    int u,v,w;
    edge(){}
    edge(int u,int v,int w):u(u),v(v),w(w){}
    bool operator<(const edge& t){
        return w<t.w;
    }
};
struct Bin{
    vector<int>f;
    Bin(int n){
        f.assign(n+1,0);
        for(int i=1;i<=n;i++)f[i]=i;
    }
    int find(int x){
        return f[x]==x?x:f[x]=find(f[x]);
    }
    bool merge(int x,int y){
        int fx=find(x);
        int fy=find(y);
        if(fy==fx)return false;
        f[fy]=fx;
        return true;
    }
};
void Silverwolf(){
    int n,m;
    cin>>n>>m;
    vector<edge>edg(m+1);
    for(int i=1;i<=m;i++){
        int u,v,w;
        cin>>u>>v>>w;
        edg[i]=edge(u,v,w);
    }
    sort(edg.begin()+1,edg.end());
    vector<edge>e2;
    Bin b(n);
    Tree tr(n);
    for(int i=1;i<=m;i++){
        auto [u,v,w]=edg[i];
        if(!b.merge(u,v)){
            e2.pb(edge(u,v,w));
        }else{
            tr.add(u,v,w);
        }
    }
    tr.work();
    for(auto [u,v,w]:e2){
        if(w<tr.dis(u,v))return cout<<"No\n",void();
    }
    cout<<"Yes\n";
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    // int T;cin>>T;while(T--)
    Silverwolf();
    return 0;
}
/*

3 3
1 2 3
2 3 4
3 1 100

3 3
1 2 3
2 3 4
3 1 2
*/

Q

长度不足\(3\)的一定可以建出唯一的二次函数。

否则,检查相邻三项的二次函数\(A,B,C\)值,看看是否可以扩展即可。

队友写的。

#include<bits/stdc++.h>
#define int long long
#define fi first 
#define se second
#define pb push_back
using ll=long long;
using namespace std;
const int N=1e6+10;
vector<int> getABC(int p0,int p1,int p2){
    //vector<pair<int,int>> ans(3,{-1,-1});
    //这里令p0的x值归0
    int c=p0;
    //a+b+c==p1
    //4a+2b+c==p2
    //2a+2b+2c==2p1
    //=>
    //a=(p2-2*p1+c)/2
    int a_up=p2-2*p1+c;
    int a_down=2;
    //4a+4b+4c==4p1
    //=>
    //2b+3c==4p1-p2
    //b=(4*p1-p2-3c)/2
    int b_up=4*p1-p2-3*c;
    int b_down=2;

    //不如直接c*2上去
    return {a_up,b_up,c*2};
}

void Silverwolf(){
    int n;
    cin>>n;
    vector<int> nums(n);
    for(auto &x:nums)
        cin>>x;

    if(n<=3){
        cout<<1<<endl;
        return;
    }

    int ans=1;
    vector<int> cur_abc=getABC(nums[0],nums[1],nums[2]);
    for(int i=3;i<n;++i){
        vector<int> rst=getABC(nums[i-2],nums[i-1],nums[i]);
        if(rst[0]==cur_abc[0])
            continue;
        ++ans;
        if(i+3>=n)
            break;
        cur_abc=getABC(nums[i],nums[i+1],nums[i+2]);
        i+=2;
    }
    cout<<ans<<endl;
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int T;cin>>T;while(T--)
    Silverwolf();
    return 0;
}

DAY2

不好玩!讨厌数学题!

赛时切了六个题,这里按题目顺序稍微写点题解吧,计划补一下\(\text{F}、\text{K}\).

B

考虑贪心策略。

如果出现了某个点被两个区间覆盖,结果一定是无解,所以我们将\((l,-1)\)\((-1,r)\)先填成\((l,l)\)\((r,r)\),判定一下是否出现了一个点被两个及以上区间覆盖的情况,可以直接按左端点排序,也可以离散化后差分。

对于\((-1,-1)\),我们可以在任意位置填上这个东西,记录一下其数量,假设为\(cnt\).

对于剩余要填的\((l,-1)\)\((-1,r)\),假设当前空余区间是\([L,R]\),贪心处理一下整段的最小贡献,假设按端点排序后的待处理队列为\(vt\)

  • \(vt_0=(l,-1)\land l\not=L\),我们需要用\((-1,-1)\)填上\([L+1,l]\)的贡献
  • \(vt_{m-1}=(-1,r)\land r\not=R\),我们需要用\((-1,-1)\)填上\([r+1,R]\)的贡献
  • \(vt_i=(-1,r)\land vt_{i+1}=(l,-1)\land r+1\not=l\),我们需要填上\((r+1,l)\)的贡献

若我们剩余的\((-1,-1)\)段数不足了,直接判无解。

复杂度瓶颈在于排序,因此我们得到了\(O(n\log n)\)的做法,代码实现不难。

D

\(k\)是奇数的情况,那么序列中间的数必须是\(mid\)本身,枚举位置,检查前后是否各有\(\frac{k-1}{2}\)个位置即可。

\(k\)是偶数,那么序列中间的两个数必须满足\(x_1+x_2=2\times mid\),设\((x_1<x_2)\),枚举\(x_1\)找最近的\(x_2\)的位置,检查前后是否各有\(\frac{k-2}{2}\)个位置即可。

F

考虑到,斐波那契数列的增长速率是非常快的,在\(n\)比较大的时候,恰好有$\frac{F_{n+1}}{F_{n}}\approx \phi $,其中 $\phi=\frac{\sqrt 5+1}{2} $。

\(n\)较大的时候,可以用\(F_n\approx \frac{\phi^n}{\sqrt 5}\)拟合。

这种计数显然和位置无关,因此我们可以对序列从小到大排序,枚举大的那个,打表发现,满足\(x<y\land x+y∈Fib\)\(x\)最多两个,不妨将这两个都找出来,将斐波那契序列前\(10^8\)项求出,并哈希处理,取一个大质数,接下来我们只需要估算\(y\)附近的斐波那契项,这样已经转化成了前缀\(\text{map}\)表经典问题。

\(y=\frac{\phi ^n}{\sqrt 5}\),那么就有\(n=log_{\phi} \sqrt 5y =\log_{\phi} \sqrt{5}+\log_{\phi} y=\frac{\lg \sqrt 5}{\lg \phi}+\frac{\lg y}{\lg \phi}\)

其中所有项都可以暴力求出 ,而\(\lg y\)的大小实际上就是\(y\)对应的高精度字符串的\(len-1\)

为保证正确性,我们在\(n\)附近枚举\(25\)项左右。

时间复杂度\(O(10^8+50\times n+n\log n)\)

G

零和博弈。

\(\text{Bob}\)的策略是删掉每一列中较大数,留给\(\text{Alice}\)的就只能是每一行的最小数,取最大值即可。

J

\(O(n^3)\)暴力枚举即可。

K

首先出现环一定无解。

对于一个\(x\),其邻边一定是\(2x\)\(2x+1\)\(\lfloor \frac{x}{2} \rfloor\),所以当某个点度数超过\(3\)的时候也无解。

不妨考虑\(dp\),以某个点为根,保证根节点的度数一定为\(1\)\(2\)

设:\(dp_{u,0/1}\)分别表示以\(u\)为根的子树,根节点设为\(0/1\)时的最小贡献,当选作\(0\)时,它的子节点的数量只能选取\(1\)个,当选作\(1\)时候,它的子节点的数量可以是\(1\)\(2\)个。

不难发现,每颗子树内的答案与根的选择有关,我们\(dp\)维护一个线性函数:\(ax+b\)表示根节点选\(x\)时以它为根的子树的贡献。

讨论一下转移:

  • 若子节点个数为\(1\),设其子节点为\(v\),且\(dp_{v,1}=ax+b\),则\(dp_{u,0}=a(x+1)+b,dp_{u,1}=a(2x)+b\)。且该情况可取当且仅当子树深度不超过\(32\)
  • 否则设其子节点为\(v_1,v_2\),且\(dp_{v_1,1}=a_1x+b_1,dp_{v_2}=a_2x+b_2\),则\(dp_{u,1}=a_1(2x)+b_1+a_2(2x+1)+b_2\),翻转一下\(v_1,v_2\)的位置也是一样的。该情况可取当且仅当子树深度不超过\(31\)

换根\(dp\)再跑一遍。

代码实现将\(dp\)采用\(Info\)类的方式实现会比较简单。

L

由于排列是随机生成的,那么下一格期望的增长量是\(\frac{n}{2}\)

那么\(len^2=\frac{n}{2}len\)的解将取在\(len=\frac{n}{2}\)附近。

我们的策略是,在\(\frac{n}{2}\)和原点附近各取\(D\)个点枚举判断,\(D=1000\)可以容易通过。

时间复杂度\(O(Dn)\)

M

贪心,从大到小排序,取前\(2^i(0\leq i\leq n)\)的最大值即为答案。

Moscow

还算一个比较有意思的场吧,感觉赛时状态不是特别好。

A

二维序列,\((a_i\% m_1,a_i\% m_2)\),按前者升序排序,相同时候后者降序排序。

如果第二维出现了\(j>i\land a_j>a_i\)的位置则构造不出方案,否则一定可以。

划分出若干个区间\([l,r]\)全相等,其方案数就是\(\prod (r-l+1)!\)

B

手玩一下样例,发现前\(\frac{n}{2}\)和后\(\frac{n}{2}\)个数不会跨过中间的分界线,且\(\text{R}\)操作后后一定是按前一半降序且后一半升序。

最后一次\(\text{R}\)操作排序一下,否则模拟即可。

E

考虑枚举将哪个位置用完后,分配给另外一个位置使用。

直接写个暴力递归。

这样可以得到一个\(O(24^2 T)\)的做法。

F

考虑朴素版本的区间\(dp\),设计\(dp\)状态为:\(dp_{l,r}\)表示区间\([l,r]\)已经被完全检测过的最小贡献值,答案即为\(dp_{1,n}\)

转移时枚举传送门,要么划分成两个更小的区间,设其为\([l_1,r_1],[l_2,r_2]\),这时的转移式是\(dp_{l_r}=min(max(dp_{l_1,r_1},dp_{l_2,r_2})+a_i)\),这部分的转移是无后效性的。

要么划分成另一个长度相等的区间,设其为\([l_3,r_3]\),这时的转移为 \(dp_{l,r}=min(dp_{l_3,r_3}+a_i)\),这部分的转移是有后效性的,所以要对这些区间跑最短路。

前者复杂度 \(O(n^3)\),后者远无法跑到的复杂度上限是\(O(n^3\log n)\)

I

通信题。

首先,贡献的上界在\(2\times 10^6\),题目启发我们可以用\(2000\times x+y\)来表示。

\(2000\)个位置中一定存在至少一个位置,\(y\)的取值是\(0\)\(1\)

那么,用\(\text{Info}\)的前\(1000\)个位置\(([0,999])\)用来做\(x\)的码,剩下一个位置\(1000\),用来做奇偶校验码,检查\(y=0\)还是\(y=1\)即可。

M

贪心的,显然从最大值往四周吞。

贡献就是\(\sum a_i-max \ a_i\)

[The 3rd Universal Cup. Stage 1: St. Petersburg ](The 3rd Universal Cup. Stage 1: St. Petersburg )

C

考虑从后往前添加点,记没加入的点为\(0\),加入的点中若为\(1\)则记作\(1\),否则记作\(-inf\),线段树维护最大子段和。

D

由于要求必须有序,所以二分是行不通的。

前半天,我们按照\(49,48,47.....32\)这样询问,找到第一次断点的位置。

然后在第二次后半天暴力询问。

次数刚好是\(50\)次。

H

\(10\)一定不会出现,所以答案是\(min(n+1,10)\)

J

留坑,还不会。

K

模拟题。

N

首先题目给的范围提示的比较明显,将原图的形态先存在来。

然后用\(\lceil{log_2 n}\rceil\)存二进制编号。

设我当前在使用\(n+1,n+2,n+3\)这三个多余的节点。

考虑构造一个只有一个点的度数为\(n\)的图,我们将\(n+1\)连向所有\([1,n]\)的节点,如果连完后存在\([1,n]\)中的某个节点的度数恰好是\(n\),将那个点连向\(n+2\)

这样我们确定了图的形态。

接下来我们将\(n+3\)指向二进制最高位的节点,并且将二进制的相邻两位之间连边,这样就解开了所有的二进制编码。

但是这种情况当\(n=3\)时要特判,我们将一行的度数\([0,7]\)二进制压缩,分别代表\((1,2)、(1,3)、(2、3)\)这三条边即可。

O

类似斐波那契数列,递归解一下\(f_2\),再递推回来即可。

The 3rd Universal Cup. Stage 18: Southeastern Europe

A

设选定根,操作次数为\(n-cnt[dep_i\leq 2]\),所以选度数最大的节点作为根遍历即可。

C

设你当前有两个集合\(A、B\),设\(near(A,B)\)表示\(A、B\)两集合是否相邻,设\(connect(A,B)\)表示两集合是否中间恰好有一个点将其联通了起来。

考虑到\(ask(A)+ask(B)=ask(\{A,B\})-k_1near(A,B)-k_2connect(A,B)\),即当\(ask(A)+ask(B)-ask(\{A,B\})>0\)时,这两个集合处在不同的联通块中。

我们维护一个联通块,每次从剩余节点,看看能不能二分得到一个新的未联通节点,并加入。

这样的次数瓶颈是\(O(n\log n)\)

D

先手的策略一定是将最大的那个数拿走。

那么对于后手,只需要判断剩下的\(sum\geq n\)是否成立即可。

F

(感觉思路基本上都有,但是差了点火候,看了点提示切的)。

首先,判断\((i,j)\)对是否好的,只需要拿出分别的最小、最大值,很好证明,当且仅当\([mn_1,mx_1],[mn_2,mx_2]\)有交的情况,这个对是好的,所以将所有的袋子只选出最小值\(mn\)和最大值\(mx\)\((i,j)\)是否好,不会有变化,这样我们已经将答案约束在了\(2n\)

我们可以选择将一些区间删除,留下袋子中的某个点。

当删除某个区间时,必须满足,覆盖该点的区间的数量\(cnt_1\)=和该区间相交的区间数量\(cnt_2\)(包含也算的)。

且,当删除某个区间时,其他与该区间覆盖的区间就不能被删除了。

对于\(cnt_1\),我们可以差分加前缀和求出。

对于\(cnt_2\),这是个很经典的问题,设当前的区间为\([l,r]\),不妨算出满足\(R< l\)的区间数量和\(L>r\)的区间数量,用总数去减。

这样判定一个区间是否用一个点替换我们就做完了。

将这些区间按左端点排序,设\(dp_{i}\)记录当前已经确定了前\(i\)个区间的最大贡献,我们维护一下与当前区间还有交集的区间,可以用\(\text{set}\)维护,不难想到的转移方程:\(dp_{i}=max (dp_{j})[\text{i and j are disjoint}]+1\),我们用\(set\)维护出来的位置就是不能被转移的位置,对于可以转移的位置,维护一下最大值即可。

综上,我们在\(O(n\log n)\)时间复杂度内得到了答案。

G

\(dp_{i,0/1}\)表示当前以值域\(i\)结尾,且当前和上一个位置相等、不等的最大贡献。

线性\(dp\)

H

问题可以转化成,是否可以找到\(n\)个逆序对。

贪心地考虑相邻两列,将当前列从小到大排序,然后从前面的所有剩下的数中,用\(set\)维护一下当前数的后继,放不下则留给后面的列。

J

考虑\(cnt_X\)记录的是\(X\)这个温度出现的次数。

考虑相邻的三项,若当前数既不为最大值又不为最小值,则将\(X\)值域的贡献更新为\(n-cnt_X\)

否则更新为\(n-cnt_X+1\)

即用最小值更新最大值,然后当前值就变成最大值了。

K

不难发现,这样的操作序列实质上是将原串转化成了这种形式:\([cnt,ch]\)表示连续\(cnt\)\(ch\)这个字符。

线段树,维护当前的前缀和。

考虑\([l,r]\)完全包含的区间\([L,R]\),这之间有:\(pre_{i}=2\times (pre_{i}-pre_{L-1})\),可以拆成区间乘\(2\)和区间加操作。

L

保留某个后缀\(m,m+1...n-1,n\)不动,将剩余部分都移到\(1\),用值域线段树维护某个值的位置即可。

2024ICPC上海/The 3rd Universal Cup. Stage 29: Metropolis

比较edu的一场,感觉是吸取了很多教训吧。

被陈队长带飞的一级,vp银牌倒三。五题罚时879。

我很战犯啊!

B

由于行为是未定义的,我们可以选择遍历的顺序。

我们用一个\(\text{set}\)维护点的连边。

若当前\(\text{set}\)已经空了,那我们直接退出是没问题的。

若当前非空,且当前\(\text{set}\)中没有当前访问点,我们这条边必须加。

当访问到一个点,将其从其所有邻边中删除。

时间复杂度\(O(n\log n)\)

C

队友写的。

分类讨论题。

拿奇数的那个人,可以通过一次操作去干扰对手,改变胜负状况。

即,考虑最小的奇数为\(x\),检查\(2x\leq r\)是否成立即可。

D

队友打表打出了一些后\(6\)位的结论。

我们只需要贪心地将前面的\(1\)尽可能往后移动,检查后\(6\)位的\(mask\)值。

(此处我半小时内实现了三个假做法)

注意到,我们可以这样执行操作:

\(111100000->1011100000\)......

这等价于将第二个\(1\)和第一个\(0\)交换位置,可以快慢指针维护。

事实上,有解性,只与最后四位有关。(我开局口胡了这个结论,但是自己都不信,然后滚去签到了)

当最后四位=\(??00\)时,显然有解。

当最后一位为\(1\),只需要满足:\(1xy1\)就有解,只要\(x>0\lor y>0\)就有解。

流程如下:

\((inf,inf,0,inf)=(inf,inf-1,inf,0)=(inf,1,inf,0)=(inf-1,inf,0,0)\)

\((inf,0,inf,inf)=(inf-1,inf-1,0,inf)\),然后重复上过程。

\((inf,inf,inf,inf)=(inf,0,inf,inf)\),然后重复上过程。

当倒数第二位为\(1\),只需要倒数第四位为\(1\)就有解。

\((inf,0,inf,0)=(inf-1,inf,0,0)\)

\((inf,inf,inf,0)=(inf,0,inf,0)\),然后重复上过程。

\(O(n)\)

G

考虑二分答案,二分是否有\(\lceil\frac{n}{2}\rceil\)个数是\(\geq mid\)的。

不妨对于每条斜线匹配一些竖线。

\(a=0\),只需检查\(b\geq mid\)是否成立。

\(a>0\),合法的位置是\(ax+b\geq mid\),即\(x\geq \lceil \frac{mid-b}{a}\rceil\)

\(a<0\),合法的位置是\(ax+b\geq mid\),即\(x\leq \lfloor\frac{b-mid}{-a}\rfloor\)

发现这是按\(c_i\)排序后的一段前缀或后缀,所以贪心地优先分配小区间是不劣的。

本题的一个坑点是:除法是向零取整,而不是向下取整的,所以这部分需要一堆分讨。

\(O(n\log A\log n)\)

I

从大到小排序。贪心分配。

\(10^9>998244353\),所以要格外注意取模。

且,判断是否有\(0\)也不能检查最大的\(k\)个乘积乘起来。

The 3rd Universal Cup. Stage 13: Sendai

B

对于每个点,找到左边第一个比它大的位置,\(l_i\)

E

注意到\(2\)操作往前推至多\(60\)次,将操作存在下模拟即可。

时间复杂度\(O(60n)\)

H

队友写的。

每次取\(i\mod n\)最大的位置,然后令\(i+1\)

I

队友写的。

考虑选择一个点,构造一个菊花图,这样将图划分成了两个部分。

剩下的\(n\)次操作,每次拿出一个红和一个蓝,去询问这两个点,不管是红或蓝,都可以减少一个不和中间块联通的点。

\(2n\)次询问是足够的。

M

如果没有不允许两步走同一条边的限制,那么就是矩阵快速幂板子。

考虑容斥一下重复的路径,即\(u->v->u\)的路径。

\(dp_i\)是经过\(i\)条边,且到\([1,n]\)中的每个点的距离是\([1,n]\)的方案数。

\[dp_i=\begin{pmatrix} a_{11} & a_{12} & \cdots & a_{1n} \\ a_{21} & a_{22} & \cdots & a_{2n} \\ \vdots & \vdots & \ddots & \vdots \\ a_{n1} & a_{n2} & \cdots & a_{nn} \end{pmatrix}\times dp_{i-1}-\begin{pmatrix} d_{1} & 0 & \cdots & 0\\ 0 & d_{2} & \cdots & 0 \\ \vdots & \vdots & \ddots & \vdots \\ 0 & 0 & \cdots & d_{n} \end{pmatrix}\times dp_{i-2} \]

这里,\(d_i\)指的是每个点的度。

值得注意的是,对于第一次后的\(d_i\)要全部减去\(1\),因为不可能从上一个位置转移过来。

考虑怎么优化这个式子,经典地,将其写成分块矩阵,其中\(A\)是连边矩阵,\(D\)是度数的矩阵。

\[\begin{pmatrix} dp_i \\ dp_{i-1} \end{pmatrix} = \begin{pmatrix} A & -D \\ I & 0 \end{pmatrix} \times \begin{pmatrix} dp_{i-1} \\ dp_{i-2} \end{pmatrix} \]

我们得到了\(O(n^3\log k)\)的做法。

The 2nd Universal Cup. Stage 2: SPb

A

容易证明,最后将这五个字符移动到目前\('b'\)所在的位置是不劣的。

B

模拟。

D

考虑\(n<m\)的情况

将第一列和最后一列填满。

\(n\)是奇数,用最中间那行填成一排。

\(n\)是偶数,用最中间那行填\(2\)个空两\(2\)个构造。

\[\begin{bmatrix} 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 \\ 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 \\ 1 & 0 & 0 & 0 & 1 & 1 & 1 & 1 & 1 & 0 & 0 & 0 & 1 \\ 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 \\ 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 \end{bmatrix} \]

\[\begin{bmatrix} 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 \\ 1 & 0 & 0 & 0 & 1 & 0 & 1 & 0 & 0 & 0 & 1 \\ 1 & 0 & 0 & 0 & 1 & 0 & 1 & 0 & 0 & 0 & 1 \\ 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 \end{bmatrix} \]

\(n>m\)同理。

特判\(n\leq 2,m\leq 2,n=m\)的情况。

G

赛时居然想了一个线段树+根号分治的离谱做法,还收到了wrong answer!那真的是一点儿没招了!

根号分治是正确的,设\(B\)是分界点。

当一个点的度数满足\(du_u\leq B\)时,不妨直接暴力,这样的复杂度是\(O(qB)\)

一个边被连接的状态可以被表示成\(0,1,2\),发现\(0,2\)是等价的,我们不关心,所以不妨用\(\text{bitset}\)的异或操作快速维护。

\(du>B\)的点不会超过\(\frac{2m}{B}\)个,这部分的复杂度是\(O(\frac{qn}{w})\)

根号分治的原因主要是下半部分会超内存,所以\(B\)差不多取个\(\sqrt {2m}\)就可以了。

I

手玩样例,分奇偶讨论。

J

两个传送门必然有交。

枚举\(A\)到哪个传送门,枚举\(B\)到哪个传送门,暴力构造方案即可。

2025ICPC西安

好像不太能放链接,能写个人题解吗,反正我很菜就是了

vp被队友带银了!

五题罚时562吧。

F

仔细分析一下约束,两只企鹅要相遇,一定满足:两只企鹅相向行走,或一只企鹅已经静止。

不妨按\((time,type,u,v)\),表示当前时间,当前相遇的类型\(type\)\(type=1\)表示是相向行走,否则表示后者已静止。

写了个超级奇怪的\(bfs\)

随手一交三脸懵逼!

时间复杂度\(O(n\log n)\)

G

从小到大排序、从大到小排序模拟一下即可。

I

一个性质是,若\((i,j)\)是相连的,那么有:

  • \(f_{i,j}\oplus f_{i,i}= j\)
  • \(f_{i,j}\oplus f_{j,j}=i\)
  • 对于其他\(k\not=i\land k\not =j\),满足\(f_{i,k}\oplus f_{j,k}=i\)\(f_{i,k}\oplus f_{j,k}=j\)

这样可以处理出每个点的邻边。

我分析了下复杂度,可能是\(O(n^2\sqrt n)\)的,就让队友交了。

J

队友讨论/写这题的时候我在被\(L\)控到超级红温,不知道题意、做法。

L

多边形非退化的条件是,\(n-1\)条较短边的和大于最长的边。

首先,处理一下每个位置往前能扩展成多边形的最短长度,二分可维护。

然后贪心地选最右边那个这种位置。

选不了就往左扩展左端点。

时间复杂度\(O(n\log n)\)

笑点解析:这题我状态真有点崩盘,\(\text{100 min}\)才过这个题。

2024ICPC昆明

C

打表观察贡献的转移是:\(x=x+\lceil \frac{x}{k-1}\rceil\)

整出分块的性质可得:\(\lceil \frac{x}{k-1}\rceil\)的取值至多有\(\sqrt n\)个。

设当前\(t=\lceil \frac{x}{k-1}\rceil\),此时,\(x\)的取值将在\([(k-1)\times t,k\times t-1]\),因此发生改变的位置发成在$cnt=\lceil \frac{k\times t-1-x}{k-1}\rceil $的位置。

\(x+cnt\times t>n\),这时,我们可以记录答案。

综上,我们得到了\(O(\sqrt n)\)的做法。

E

和交互一点没有关系的交互题。

首先,不妨先考虑将所有距离为\(k\)的点处理出来。

然后贪心地将其放入方程组中,这一步可以用线性基维护。

然后高斯消元解方程即可。

时间复杂度\(O(30\times \frac{n^3}{w})\)

G

首先打了个\(n^2\)\(dp\),找找\(i,j\leq 5000\)最多的次数,发现最多是\(14\)次.

类似地,你想想,将整个序列消掉的贡献也不会要太多次.

暴力模拟剪枝即可.

H

你对这\(n\)个点做个极角排序,然后的贡献就是相邻的\(k\)个点之间的角度.

J

签到,没太看思路.

L

首先,你的怪物肯定会贪心地尽可能地去打对方血量小的,直至其能爆炸.

我们不妨记录一下我们能攻击的次数\(cnt\).

双指针搞一下,假设当前已经能爆炸的怪物是\(boom\),若\(a_i\leq boom+1\),则说明这只怪物能爆炸,若\(b_j\leq boom\)则说明对手的怪物能爆掉,若不能我们就将其补到\(boom\)即可.

时间复杂度是\(O(n+m)\).

M

不难发现,按着如下方式构造即可:
\(1,2,4,7\\3,5,8,11\\6,9,12,14\\10,13,15,16\)

这样斜着构造就行.

posted on 2025-10-01 21:21  __Silverwolf  阅读(18)  评论(0)    收藏  举报

导航