• [Contest on 2022.6.29] 再见!


    没想到一年前外培的题目放到了今天的考试题,这是为什么呢?非常的奇妙啊!

    所以下面的内容是去年写的,非常的奇妙啊!

    \(\mathcal{T}_1\) 对王之王

    Description

    小 W 希望写出一副对联,让它体现 \(n\) 行的相生相克。

    小 W 的这副对联包含上联、下联和横批,各有 \(n\) 个字。每个字根据其偏旁的类型,可以记为一个 \(0\)\(n − 1\) 之间的整数。小 W 希望上联、下联和横批都是 \(0\)\(n − 1\)排列,我们将其分别记为 \(a, b, c\).

    小 W 还希望上联、下联、横批都能体现 \(n\) 行的相生相克。具体来说,小 W 会有三种标准来衡量这副对联是否能体现 \(n\) 行的相生相克:

    1. 对于任意 \(0 \leqslant i < n\),有 \(a_i + b_i ≡ c_i \pmod n\)

    2. 对于任意 \(0 \leqslant i < n\),有 \(a_ib_i ≡ c_i \pmod n\)

    3. 对于任意 \(0 \leqslant i < n\),有 \(a^{b_i}_i ≡ c_i \pmod n\),注意在本题中 \(0^0\) 是无意义的。

    现在,小 W 希望你在符合第 \(\rm T\) 种标准的条件下,构造出一副长为 \(n\) 的对联。

    \(2\leqslant n\leqslant 2\cdot 10^5\).

    我的想法

    \(\text T=1\) 的情况就想到了 这道题,在考场上还 yy 了个感性理解。

    \(\text T=3\) 打了个暴力走人。

    Solution

    \(\text T=2\)

    结论 1:\(n\) 无平方因子。

    证明:

    设存在质数 \(p\) 使得 \(p^2\mid n\) 且此时有解。显然 $A_x ,B_x $ 中只要有一个是 \(p\) 的倍数,\(C_x \bmod n\) 就会是 \(p\) 的倍数,由于 \(A,B,C\)\(p\) 的倍数个数相同,因此必须满足当 \(p\mid A_x\) 时,有 \(p\mid B_x\).

    考虑 \(C_x =p\),此时 $p\mid A_x ,p\mid B_x $,故 $p^2\mid C_x $,且 \(p^2\mid (C_x\bmod n)\),所以矛盾。

    结论 2:只有 \(n=2\) 有解。

    证明:

    首先 \(n\) 必须无平方因子。任取质数 \(p\) 满足 \(p\mid n\)。设 \(m=n/p\),显然 \(\gcd(m,p)=1\).

    考虑集合 \(S=\{ xm\mid x\in [1,p-1],x\in \mathbb{N}\}\),类似于证明 \(n\) 无平方因子的方式可以证明 \(A_x \in S\Longleftrightarrow B_x \in S\Longleftrightarrow C_x \in S\).

    那么有

    \[\begin{aligned} \prod_{x\in S}x&=\prod_{A_x \in S}A_x =\prod_{B_x \in S}B_x =\prod_{C_x \in S}C_x \\ &=\prod_{k=1}^{p-1}km\\ &=m^{p-1}(p-1)!\\ &\equiv 1\times (-1)\pmod p\\ &\equiv -1\pmod{ p}\end{aligned} \]

    \(\displaystyle\left(\prod_{A_x \in S}A_x\right) \cdot \left(\prod_{B_x \in S}B_x\right) =\prod_{C_x \in S}C_x\),故 \((-1)\times(-1)\equiv -1\pmod p\),只有 \(p=2\) 满足条件,因此 \(n\) 的质因子只有 \(2\),只有 \(n=2\) 符合条件。

    \(\text T=3\)

    数学题滚出 OI!!!

    \(\mathcal{T}_2\) 伊莉斯

    Description

    你处于一个 \(n×n\) 的网格空间中,一开始你位于 \((1, 1)\),而「门」位于 \((n, n)\)

    你每一时刻可以选择从 \((i, j)\) 移动向 \((i, j + 1)\) 或者 \((i + 1, j)\)(我们记为向上和向右), 当然,你不能离开这个空间。

    伊莉斯拥有 \(c^2\) 个魔眼,它们在网格上形成一个方阵,即位置 \((a + i, b + j)(0 \leqslant i < c, 0 \leqslant j < c)\) 上都有一个魔眼。初始它们都有一个阀值 \(t\),如果某一时刻你移动到了 \((x, y)\),那 么位于位置 \((i, j)\) 的魔眼阀值将会减少 \(|x − i| + |y − j|\),一旦有一个魔眼的阀值减到了 \(0\) 以下,你将会被伊莉斯石化(即使你已经到达了「门」)。但由于你的强对抗力,你可以走到存在魔眼的位置上。

    现在,作为霸主权能的拥有者,你想要判断出是否存在一条路径可以安全地到达「门」。

    如果不存在一条安全的路径,输出 Again,否则输出一行一个由 RU 两种字符构成的长 \(2(n−1)\) 的字符串,表示你每一个时刻移动的方向为向右和向上。如果存在多种方案,输出对应字符串字典序最小的方案。

    \(n\leqslant 2\cdot 10^6,1\leqslant t\leqslant 10^{14}\).

    我的想法

    经过一只魔眼 \((x,y)\) 的最短路:从 \((1,1)\) 走到 \((x,y)\),再从 \((x,y)\) 走到 \((n,n)\).

    然后还是不会,打了暴力走人。

    Solution

    \(\color{red}{\text{Disclaimer}}\):以下涉及大量感性证明。


    先考虑比较简单的情况 —— 只有一只魔眼。由于题目只要求在路径合法的限制下最小化字典序,所以直接使用上文提出的最短路是不科学的。我们需要尽可能向右走。事实上,对于在 \((a,b)\) 右下方 的点 \((i,j)\),此时的最短路一定是从 \((i,j)\) 向上走走到 \((i,b)\),再走到 \((n,n)\)

    具体可以这样证明(其实这也是上文提到的最短路构造方案的证明):假设从 \((i,j)\) 开始往右走了几步,最后从 \((i,p),p>b\) 进入 \((a,b)\) 的右上方。这个方案一定比直接走到 \((i,b)\),从 \((i,b)\) 向右走到 \((i,p)\) 更劣。你可以画几圈关于 \((a,b)\) 的等距线来观察。

    从这里也可以发现,最劣的情况一定是先向右走到 \((n,j)\),再向上走到 \((n,n)\).

    于是可以得出我们的策略:先向右走到 \((a,1)\),再判断此时向右走一步,之后根据最优方案能否安全到达,不停尽力向右走即可。

    回到原问题。先考虑一下如何判断方案的存在性。

    首先还是从 \((1,1)\) 随便走到 \((a,b)\) 这个位置,因为在这个区间魔眼与人的距离相当于魔眼与 \((a,b)\) 的距离加上人与 \((a,b)\) 的距离。这是固定的。

    方案是否合法只取决于四个角上的魔眼。但是我并不会证明。所以对于内部,用 "右上上右右上上……右" 的走法。这是因为只要是从左下走到右上,右上左下两只魔眼的阈值减少量就是固定的,比如左下那只,初始减少 \(\delta=0\),之后的减少量每次都能增加 \(1\)。而这个方案也能保证左上右下两只魔眼的总阈值减少量相同(需要说明的是,它们的阈值减少量总和总是固定的)。

    \((a,b)\) 走到 \((n,n)\) 仍然是随便走。

    现在考虑如何使字典序最小。迁移一只魔眼的思路,先尽量往右走,再判断是否合法。首先可以将起点挪到 \((a,1)\)。对于在 "魔眼区左下角(指 \(x<a,y<b\) 的区域)"、"魔眼区"、"魔眼区右上角" 的右下角区域有一个共同的最优策略 —— 向上走。

    现在只需要考虑魔眼区的最优策略。首先能想到整体路径是先走到魔眼区右上角,再随便走,于是上文的 "右上左下两只魔眼的阈值减少量是固定的" 和 "左上右下两只魔眼的总阈值减少量总和固定" 这两个结论仍然成立。

    于是只用保证左上右下两只魔眼的阈值不小于零即可。考虑左上角魔眼的阈值减少量变化情况,事实上这也是上文单只魔眼的情况。同时,由于左上角魔眼阈值减少量越小等价于右下角魔眼阈值减少量越大,判断是否存在一种方案使得两只魔眼阈值不小于零也是比较容易的。

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

    Code

    代码实现有一点恶心,但是调试还是比较顺利(?

    有一个 \(\text{corner case}\) 没有考虑到。

    # include <cstdio>
    # include <cctype>
    # define print(x,y) write(x), putchar(y)
    
    template <class T>
    inline T read(const T sample) {
        T x=0; char s; bool f=0;
        while(!isdigit(s=getchar())) f|=(s=='-');
        for(; isdigit(s); s=getchar()) x=(x<<1)+(x<<3)+(s^48);
        return f? -x: x;
    }
    template <class T>
    inline void write(T x) {
        static int writ[50], w_tp=0;
        if(x<0) putchar('-'), x=-x;
        do writ[++w_tp]=x-x/10*10, x/=10; while(x);
        while(putchar(writ[w_tp--]^48), w_tp);
    }
    
    # include <vector>
    # include <iostream>
    using namespace std;
    typedef long long _long;
    
    const _long infty = 1e18;
    
    vector <char> ans; 
    int n,a,b,c,x,y,X[4],Y[4],L; 
    _long t,d[4],ad[4],low,upp,jinx;
    
    _long Abs(const _long& x) { return x>0?x:-x; }
    int dis(int x,int y,int z,int u) {
        return Abs(x-z)+Abs(y-u);
    }
    void getMin(_long& tmp,_long& delta,const _long& A,const _long& B) {
        if(A<B) tmp=A; else tmp=B, delta-=L;
    }
    _long cost(int x,int y,int z,int u,int X,bool opt=0) {
        L = Abs(u-z); _long delta = 1ll*(1+L)*L/2, tmp;
        if(!opt) getMin(tmp,delta,dis(x,y,z,X),dis(x,y,u,X)); 
        else getMin(tmp,delta,dis(x,y,X,z),dis(x,y,X,u));
        return delta+tmp*L; // ignore the first dot
    } // 0: across; 1: vertical
    bool canReach(int x,int y,bool opt=0) {
        for(int i=0;i<4;++i) {
            ad[i] = cost(X[i],Y[i],x-1,x,y,0);
            if(opt) ad[i]=0;
            if(d[i]+ad[i]>t) return false;
        }
        if(x>a+c-1) { 
            for(int i=0;i<4;++i) {
                if(y<b) ad[i] += cost(X[i],Y[i],y,b,x,1);
                ad[i] += cost(X[i],Y[i],max(b,y),b+c-1,x,1);
                ad[i] += cost(X[i],Y[i],b+c-1,n,x,1);
                ad[i] += cost(X[i],Y[i],x,n,n,0);
                if(d[i]+ad[i]>t) return false;
            } 
        } else {
            for(int i=0;i<4;++i) {
                if(y<b) ad[i] += cost(X[i],Y[i],y,b,x,1);
                ad[i] += cost(X[i],Y[i],a+c-1,n,b+c-1,0);
                ad[i] += cost(X[i],Y[i],b+c-1,n,n,1);
                if(d[i]+ad[i]>t) return false;
            }
            ad[1] += cost(X[1],Y[1],max(b,y),b+c-1,x,1);
            ad[1] += cost(X[1],Y[1],x,a+c-1,b+c-1,0);
            ad[3] += cost(X[3],Y[3],max(b,y),b+c-1,x,1);
            ad[3] += cost(X[3],Y[3],x,a+c-1,b+c-1,0);
            if(d[1]+ad[1]>t || d[3]+ad[3]>t) return false;
            _long delta = cost(X[0],Y[0],max(b,y),b+c-1,x,1)+
                          cost(X[0],Y[0],x,a+c-1,b+c-1,0);
            _long sm = delta+
                       cost(X[2],Y[2],max(b,y),b+c-1,x,1)+
                       cost(X[2],Y[2],x,a+c-1,b+c-1,0);
            low = delta;
            upp = cost(X[0],Y[0],max(b,y),b+c-1,a+c-1,1)+
                  cost(X[0],Y[0],x,a+c-1,max(b,y),0);
            jinx = min(upp, t-d[0]-ad[0]);
            if(Abs(jinx-upp)&1) -- jinx; 
            if(jinx<low) return false;
            _long oth = sm-jinx;
            if((Abs(oth-(sm-delta))&1) || oth+d[2]+ad[2]>t) return false;
        } return true;
    }
    
    void upd(int x,int y,bool opt) {
        if(!opt)   
            for(int i=0;i<4;++i)
                d[i] += cost(X[i],Y[i],x-1,x,y,0);
        else
            for(int i=0;i<4;++i)
                d[i] += cost(X[i],Y[i],y-1,y,x,1);
    }
    
    int main() {
        freopen("elis.in","r",stdin);
        freopen("elis.out","w",stdout);
        n=read(9), t=read(9ll), a=read(9), b=read(9), c=read(9);
        x=a, y=1; X[0]=X[1]=a, X[2]=X[3]=a+c-1;
        Y[0]=Y[3]=b+c-1, Y[1]=Y[2]=b;
        for(int i=1;i<a;++i) ans.emplace_back('R');
        for(int i=0;i<4;++i) d[i]=cost(X[i],Y[i],1,a,1,0);
        while(y<b+c-1 && x<n) {
            if(canReach(x+1,y)) ++x, ans.emplace_back('R'), upd(x,y,0);
            else ++y, ans.emplace_back('U'), upd(x,y,1);
        }
        if(!canReach(x,y,1)) return puts("Again"), (0-0);
        while(x<n) ++x, ans.emplace_back('R');
        while(y<n) ++y, ans.emplace_back('U');
        for(const auto& i:ans) putchar(i); puts("");
        return 0;
    }
    
  • 相关阅读:
    1-命令格式
    android default_workspace.xml
    多维算法思考(二):关于八皇后问题解法的探讨
    C#对excel的操作
    c#读取xml操作
    一个用 C# 实现操作 XML 文件的公共类代码
    如何使用 LINQ 执行插入、修改和删除操作
    C#--编程
    LINQ常用操作
    用线性组合表示两个数的最大公约数
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/16422507.html
Copyright © 2020-2023  润新知