• NOI2018 屠龙勇士 做题心得


    今天A掉了这个题,感觉这是一个帮助我增强调试技巧的好题!!1

    题解

    首先分析,我们发现:对于每条龙,我们用什么伤害的剑,其实是确定的,与 (x) 无关,可以用简单的模拟求出这个东西。

    然后相当于是这样一个方程:

    [egin{cases} a_1 x equiv b_1 pmod{m_1}\ a_2 x equiv b_2 pmod{m_2}\ ...\ a_n x equiv b_n pmod{m_n}\ end{cases} ]

    对于每一条方程 (axequiv bpmod{m}),我们把它变形。由于我们会excrt,我们知道,肯定是变成 (xequiv bpmod{m}) 好做。

    考虑 (g=gcd(a,m))。如果 (b) 不是 (g) 的倍数,啪的一下,无解。这是显然的。否则,我们可以把 (a,b,m) 同事约去一个 (g),然后 (a,m) 就互质力!!!

    互质,那好做,变成 (xequiv b imes a^{-1} pmod{m})

    然后就做一下 excrt 就行了

    小结

    首先那个观察非常重要,不过相对容易些

    然后就是对式子的分析。就和学校里whk老师讲的做题方法一样,首先你手上要有一套方法,然后你要想,这个题目的问题,怎么转化成你手上的这些东西。

    就好比我们会excrt,会做的其实是 (xequiv bpmod{m})。而这个题目中和这个形式不同,因此我们要做转化,把它变成会做的这个形式。

    关于调试

    这题的数据卡的很死,因此尤其要小心爆long long的问题。

    有一个常识是,exgcd是不会爆的。一开始是hyh和我讲的这个事情,我后来去u群确认了一下。

    证:EI说对,那就是对!

    其它地方会不会爆呢?这我们不好直接靠脑子想。先把代码写出来,过小样例再说。如果小样例你感觉太水,可以手造一些。手造数据的能力很重要,后面的对拍都需要靠手造样例。

    关于造数据:
    您可以先生成一个 (x),再随机一些 (a)(m),计算 (axmod m),得到 (b)

    有一件事情是,我们需要保证所有 (m)(lcm) 不超过 (1e12)

    这并不困难,我们手造一个 (1e12) 左右,因数比较多的数。然后每次的 (m) 就随机取它一个因数就行

    这里又有一个小技巧:随机取因数,不需要先求出因数,我们在造这个数的时候,就先把它分解,然后每个质数随机一个指数就行了。

    对于小数据,可以把这个数取的小一些,比如 (1e8)

    然后我们可以用 Linux 下的 -fsanitize=undefined 功能,找到哪些地方爆了long long。

    然后多调几次就行了。

    对于最后三个点,可能比较毒瘤。这里暴露的问题也许很难在调试中发现,如果实在不行就下数据。我个人感觉,靠手造数据调试,是可以做到85分的。

    代码

    本题

    #include <bits/stdc++.h>
    using namespace std;
    namespace Flandre_Scarlet
    {
        #define N   200005
        #define int long long
        #define F(i,l,r) for(int i=l;i<=r;++i)
        #define D(i,r,l) for(int i=r;i>=l;--i)
        #define Tra(i,u) for(int i=G.h[u],v=G.to(i);~i;i=G.nx(i),v=G.to(i)) if (i>=0)
        #define MEM(a,x) memset(a,x,sizeof(a))
        #define FK(a) MEM(a,0)
        #define sz(x) ((int)x.size())
        #define all(x) x.begin(),x.end()
        #define p_b push_back
        #define pii pair<int,int>
        #define fir first
        #define sec second
        int I() {char c=getchar(); int x=0; int f=1; while(c<'0' or c>'9') f=(c=='-')?-1:1,c=getchar(); while(c>='0' and c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return ((f==1)?x:-x);}
        template <typename T> void Rd(T& arg){arg=I();}
        template <typename T,typename...Types> void Rd(T& arg,Types&...args){arg=I(); Rd(args...);}
        void RA(int *p,int n) {F(i,1,n) *p=I(),++p;}
        int n,m;
        int a[N],p[N],g[N],h[N];
        void Input(int id=0)
        {
            Rd(n,m);
            F(i,1,n) a[i]=I();
            F(i,1,n) p[i]=I();
            F(i,1,n) g[i]=I();
            F(i,1,m) h[i]=I();
        }
    
        int smul(int a,int b,int m) // 龟速乘, 您可以用 __int128 代替(雾)
    	{
    		a=(a%m+m)%m; b=(b%m+m)%m;
    		int r=0;
    		while(b)
    		{
    			if (b&1) r=(r+a)%m;
    			a=(a<<1)%m; b>>=1;
    		}
    		return r;
    	}
    	int gcd(int a,int b){if (a<0) a=-a; if (b<0) b=-b; while(b)swap(a,b),b%=a; return a;}
        int lcm(int a,int b){return a/gcd(a,b)*b;} // lcm,gcd: 不会爆
        void exgcd(int a,int b,int&x,int&y) // ax+by=gcd(a,b), 这个也不会爆
        {
            if (b==0) {x=1; y=0; return;}
            exgcd(b,a%b,y,x); y-=x*(a/b);
        }
        int inv(int a,int b){int x,y; exgcd(a,b,x,y); return (x%b+b)%b;}
        bool sol(int a,int b,int&x,int&y,int c,int mod) // ax+by=c, 返回是否有解
        {
    		b=-b; // b一定是负的
            int g=gcd(a,b); 
    		if (c%g) {x=-1; y=-1; return false;}
            a/=g; b/=g; c/=g;
            exgcd(a,b,x,y); // ax+by=1
            x=smul(x,c,mod); y=smul(y,mod-c,mod);  // 小心!
    		return true;
        }
    	namespace exCRT
        {
            bool no_sol=0;
            int r[N],m[N],n; // x = r[i] (mod m[i])
    		int L=1; // 所有模数的lcm
            void clear()
            {
                n=0; FK(r); FK(m); no_sol=0; L=1;
            }
            void add(int a,int b,int mm) // 加入一条方程 ax=b (mod m)
            // a<=1e6, b<=1e12, mm<=1e12
            {
                if (mm==1) return; // 我们跳过模数为1的方程
                int g=gcd(a,mm);
                if (b%g) {no_sol=1; return;}
                a/=g; b/=g; mm/=g;
                b=smul(b,inv(a,mm),mm);  // 小心!
                ++n;
                r[n]=b; m[n]=mm;
                L=lcm(L,m[n]);
            }
            int get_sol() // 解
            {
                if (n==0) {return 0;} // 有一个sb情况就是, 所有模数都为1, 不过不判好像没事
                if (no_sol) {return -1;}
                int R=r[1],M=m[1]; // M<=1e12, R<M
                F(i,2,n)
                {
                    int x,y;
                    int m2=lcm(M,m[i]);
                    if (sol(M,-m[i],x,y,r[i]-R,m2))
                    {
    					R=(R+smul(x,M,m2))%m2; // 小心!
                        M=m2;
                    }
                    else return -1;
                }
                return R;
            }
        }
    
        multiset<int>sw; multiset<int>::iterator it,it2;
        void Sakuya()
        {
            exCRT::clear(); sw.clear();
            F(i,1,m) sw.insert(h[i]);
            int mn=0;
            // 注意到我们的每次攻击都至少要把龙打到0血以下,因此我们的x值是有下界的
            F(i,1,n)
            {
                it2=sw.upper_bound(a[i]);
                if (it2!=sw.begin()) --it2;
                int atk=*it2; // 找剑
    
                exCRT::add(atk,a[i],p[i]);
                mn=max(mn,(a[i]+atk-1)/atk); // 要打到0以下
    
                sw.erase(it2); sw.insert(g[i]);
            }
            int R=exCRT::get_sol(),M=exCRT::L;
            if (R==-1)
            {
                puts("-1");
            }
            else
            {
                if (R<mn) R=R+M*(mn-R+M-1)/M; // 这个其实就是不断的加, 直到加过下界
                printf("%lld
    ",R);
            }
        }
        void IsMyWife()
        {
            int t=I(); int Cas=0;
            while(t-->0)
            {
                ++Cas;
                Input(Cas);
                Sakuya();
            }
        }
    }
    #undef int //long long
    int main()
    {
        Flandre_Scarlet::IsMyWife();
        return 0;
    }
    

    数据生成器:

    这个代码暂时不在我手上,我明天去学校里搞吧。

  • 相关阅读:
    8. Django系列之上传文件与下载-djang为服务端,requests为客户端
    机器学习入门15
    机器学习入门14
    机器学习入门13
    机器学习入门12
    ML
    AI
    机器学习入门11
    机器学习入门10
    机器学习入门09
  • 原文地址:https://www.cnblogs.com/LightningUZ/p/15404565.html
Copyright © 2020-2023  润新知