• 「万能欧几里得」学习笔记


    一直以为这个是计数内容

    第一次看见是在 djq 的论文里,还以为是新东西( ,不过我确实还没学就是了。

    称之为欧几里得的东西,想必一定利用 \(\bmod\)\(swap\) 达到了 \(\log\) 复杂度的目的。
    这种数形结合的形式还真是有趣呢 \(\smile\)


    所谓万能欧几里得,是解决这样一种问题的:

    在平面直角坐标系上的一次函数 \(y = \frac{Px + R}{Q}\),从 \(x=0\) 扫到 \(x=L\) ,每次若直线碰到横线就执行 \(U\) ,如果碰到竖线就执行 \(R\) ,其中 \(U,R\) 是指两个具有结合律的操作,钦定经过整点时先执行 \(U\)

    Step 1. \(P \bmod Q\)

    \[y = \lfloor \frac{Px+R}{Q} \rfloor = \lfloor \frac P Q \rfloor x + \lfloor \frac{(P \bmod Q)x + R}{Q} \rfloor \]

    \(P \ge Q\) ,则在每个 \(R\) 前一定至少有 \(\lfloor \frac P Q \rfloor\)\(U\) ,那么把 \(\lfloor \frac P Q \rfloor\)\(U\)\(R\) 拼到一起,有 \(f(P,Q,R,L,U,R) = f(P \bmod Q ,Q,R,L,U,U^{\lfloor \frac{P}{Q} \rfloor}R)\)

    Step 2. \(swap(P,Q)\)

    不就是对称翻转嘛

    将原本的函数以 \(y=x\) 为对称轴翻转,也就是 \(y=\lfloor \frac{Px+R}{Q} \rfloor\) 变成了 \(y=\lfloor \frac{Qx-R-1}{P} \rfloor\) ,具体推导是设第 \(a\)\(R\) 在第 \(b\)\(U\) 之前,列出式子然后调整一下取整函数。
    这样的推导同时也保证了操作的优先级正确。

    几个问题:

    1. \(-R-1<0\)
    2. 原本 \(x=L\) 的地方可能 \(y\) 不是整数。

    针对第一个问题,由于我们知道 \(P<Q,R<Q\) ,所以 \(Q-R-1 \ge 0\) ,也即 \(x=1\) 处取值一定为正,那么把这前面一段先计算了放在前面就行。
    嗯这里提到了 \(R<Q\) ,原因是如果 \(R \ge Q\) 那我们完全可以将其直接提出常数个 \(U\)

    针对第二个问题,也是把后面的一段另外计算即可,知道了总共有多少个 \(U\)\(R\) ,算这个还是很简单的。


    实际应用时要注意 \(U,R\) 表示成多元组形式的结合。

    应用于类欧模板(省去 includedefine):
    (高度拟合pb)

    using namespace std;
    typedef long long ll;
    const int mod=998244353;
    int T,n,a,b,c;
    struct node{
    	int a,b,s1,s2,s3;
    	node(){a=b=s1=s2=s3=0;}
    	node(int A,int B,int C,int D,int E){a=A;b=B;s1=C;s2=D;s3=E;}
    	friend inline node operator*(node f,node g){
    		node ret;
    		ret.a=add(f.a,g.a);
    		ret.b=add(f.b,g.b);
    		ret.s1=((ll)f.a*g.b + f.s1 + g.s1) % mod;
    		ret.s2=((ll)f.a*f.a%mod*g.b%mod + 2ll*f.a*g.s1%mod + f.s2 + g.s2) % mod;
    		ret.s3=(((ll)f.a * g.b + g.s1) % mod * f.b % mod + (ll)g.b*(g.b+1)/2 % mod * f.a % mod + f.s3 + g.s3 ) % mod;
    		return ret;
    	}
    }U,R,I;
    node power(node x,int n){
    	node a;
    	while(n){
    		if(n&1)a=a*x;
    		x=x*x;
    		n>>=1;
    	}
    	return a;
    }
    node f(int P,int Q,int R,ll L,node a,node b){
    	if(!L)return node();
    	if(!(((ll)L*P+R)/Q))return power(b,L);
    	if(P>=Q)return f(P%Q,Q,R,L,a,power(a,P/Q)*b);
    	// if(!P)return node(0,L,0,0,0);
    	node ret=power(b,(Q-R-1)/P)*a;
    	ll len=((ll)L*P+R)/Q;
    	ret=ret*f(Q,P,(Q-R-1)%P,len-1,b,a);
    	ret=ret*power(b,L-((ll)len*Q-R-1)/P);
    	return ret;
    }
    int main(){
    	freopen("data.in","r",stdin);
    	freopen("data.out","w",stdout);
    	U.a=R.b=1;
    	scanf("%d",&T);
    	while(T--){
    		scanf("%d%d%d%d",&n,&a,&b,&c);
    		I.a=b/c;
    		node ans=f(a,c,b%c,n,U,R);
    		ans=node(b/c,0,0,0,0)*ans;
    		printf("%d %d %d\n",add(ans.s1,(b/c))%mod,((ll)(b/c)*(b/c)+ans.s2)%mod,ans.s3);
    	}
    
    	return 0;
    }
    
  • 相关阅读:
    为什么我用Ipad Pro做电子笔记和看PDF电子书
    将Chrome浏览器中的扩展程序导出为crx插件文件
    OneNote
    UPAD for iCloud
    在家和图书馆学习哪个好
    基于GRPC+consul通信的服务化框架(转)
    wrk中的lua脚本(转)
    Lua标准库(转)
    分布式队列编程:从模型、实战到优化(转)
    性能测试之-wrk(转)
  • 原文地址:https://www.cnblogs.com/Kelvin2005/p/16354619.html
Copyright © 2020-2023  润新知