Atcoder utpc2012 K-ラッピング (立体几何/置换/类欧几里得算法)
Atcoder utpc2012 K-ラッピング (立体几何/置换/类欧几里得算法)
卡在了最后一步转换上:
已知置换\(L,D\),为立方体左滚和下滚的置换。
求:
\[\prod _{i=1}^B L^{\lfloor \frac{iA}{B} \rfloor-\lfloor \frac{(i-1)A}{B} \rfloor} R
\]
(假设\(\gcd(A,B)=1\))
众所周知,置换是有结合律而没有交换律的,所以拆开来显然不现实。
考虑\(L\)的次数,可以发现要么是$\lfloor A/B \rfloor \(要么是\)\lceil A/B \rceil $。
确切的说,第\(i\)个\(L\)的次数\(P_i\)满足:
\[P_i=\lfloor A/B \rfloor+[(i-1)*A\mod B-i*A\mod B\geq B-A\mod B]
\]
把它理解到一个值域是\([0,B-1]\)的数轴上的跳跃,其实只有\(B\mod A\)个值是上取整,其它都是下取整。这样我们只需要使用类欧就可以了。
/*
{
######################
# Author #
# Gary #
# 2021 #
######################
*/
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
//inline int read(){
// int x=0;
// char ch=getchar();
// while(ch<'0'||ch>'9'){
// ch=getchar();
// }
// while(ch>='0'&&ch<='9'){
// x=(x<<1)+(x<<3)+(ch^48);
// ch=getchar();
// }
// return x;
//}
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
/*}
*/
struct cube{
int a[6];
cube(){
rep(i,6) a[i]=i;
}
bool operator == (cube oth){
rep(i,6) if(a[i]!=oth.a[i]) return false;
return true;
}
void lr(){
int od=a[0];
a[0]=a[3];
a[3]=a[2];
a[2]=a[1];
a[1]=od;
}
void dr(){
int od=a[0];
a[0]=a[5];
a[5]=a[2];
a[2]=a[4];
a[4]=od;
}
cube operator * (cube oth){
cube ret;
rep(i,6) ret.a[i]=oth.a[a[i]];
return ret;
}
cube operator ^ (LL t){
if(t==0){
return cube();
}
cube ret=(*this)^(t>>1);
ret=ret*ret;
if(t&1) ret=ret*(*this);
return ret;
}
};
LL gcd(LL A,LL B){
if(B==0) return A;
return gcd(B,A%B);
}
cube gcd(LL A,LL B,cube x,cube y){
if(B==0) return x;
return gcd(B,A%B,(x^(A/B))*y,x);
}
int main(){
LL A,B;
scanf("%lld%lld",&A,&B);
if(A==0||B==0){
puts("4");
return 0;
}
LL g=gcd(A,B);
A/=g;
B/=g;
double a,b;
a=A,b=B;
double cnt=0;
cube now;
cube tot;
cube L,R;
L.lr();
R.dr();
tot=gcd(A,B,L,R);
while(!(cube()==now)||cnt==0){
cnt+=1.0;
now=now*tot;
}
cnt*=sqrt(a*a+b*b);
printf("%.20f\n",cnt);
return 0;
}