SGU - 294 He's Circles
1、长度为N的环,涂两种颜色,无其他约束,问本质不同
显然对于旋转的每种置换,有n种旋转,每种贡献是\(2^{gcd(i, N)}\)
最终答案为\(\frac {\sum_{i = 1}^N 2^{gcd(i, N)}} N\)
当n非常大的时候无法枚举所有数,所以套路是枚举约数的贡献,显然循环节gcd为d的置换会出现\(\phi(n / d)\)次,那么答案就是
\[\frac {\sum_{d|n} 2^d\phi(n / d)} n
\]
\(2 * n / 2, .... \sqrt n * \sqrt n\) 可以把复杂度压到\(\sqrt n\).
模数互质的情况下inv(N)好求,如果不互质1、考虑过程中能不能除n 2、扩展欧几里得求逆元
没有模数所以要大数模拟
#include<bits/stdc++.h>
using namespace std;
//#define int long long
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef pair <int,int> Pii;
#define reg register
#define mp make_pair
#define pb push_back
#define Mod1(x) ((x>=Phi)&&(x-=Phi))
#define Mod2(x) ((x<0)&&(x+=Phi))
#define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i)
template <class T> inline void cmin(T &a,T b){ ((a>b)&&(a=b)); }
template <class T> inline void cmax(T &a,T b){ ((a<b)&&(a=b)); }
char IO;
template <class T=int> T rd(){
T s=0; int f=0;
while(!isdigit(IO=getchar())) f|=IO=='-';
do s=(s<<1)+(s<<3)+(IO^'0');
while(isdigit(IO=getchar()));
return f?-s:s;
}
#define dbg(x...) \
do { \
cout << #x << " -> "; \
err(x); \
} while(0)
void err() {
cout << endl;
}
template<class T, class ...Ts>
void err(const T &arg, const Ts &...args) {
cout << arg << " ";
err(args...);
}
const int maxn = 4e5 + 10;
const int N=2e5;
const int base=1e4;
const int digit=4;
const int maxl=1e5;
ll vis[maxn], pri[maxn], cnt, phi[maxn];
void init() {
vis[1] = 1; phi[1] = 1;
for(int i = 2; i < maxn; ++ i) {
if(!vis[i]) pri[cnt ++] = i, phi[i] = i - 1;
for(int j = 0; j < cnt && i * pri[j] < maxn; ++ j) {
vis[i * pri[j]] = 1;
if(i % pri[j] == 0) {
phi[i * pri[j]] = phi[i] * pri[j];
break;
}
phi[i * pri[j]] = phi[i] * phi[pri[j]];
}
}
}
struct Bignum{
int len,v[maxl];
Bignum(){len=1,memset(v,0,sizeof(v));}
void init(){v[0]=1;}
void write(){
printf("%d",v[len-1]);
for (int i=len-2;~i;i--) printf("%0*d",digit,v[i]);
putchar('\n');
}
};
Bignum operator +(const Bignum &x,const Bignum &y){
Bignum z;
z.len=max(x.len,y.len);
for (int i=0;i<=z.len;i++) z.v[i]+=x.v[i]+y.v[i],z.v[i+1]+=z.v[i]/base,z.v[i]%=base;
while (z.v[z.len]) z.v[z.len+1]+=z.v[z.len]/base,z.v[z.len]%=base,z.len++;
return z;
}
Bignum operator *(const Bignum &x,const Bignum &y){
Bignum z;
z.len=x.len+y.len;
for (int i=0;i<=x.len;i++)
for (int j=0;j<=y.len;j++)
z.v[i+j]+=x.v[i]*y.v[j],z.v[i+j+1]+=z.v[i+j]/base,z.v[i+j]%=base;
while (z.len!=1&&!z.v[z.len]) z.len--;z.len++;
while (z.v[z.len]) z.v[z.len+1]+=z.v[z.len]/base,z.v[z.len]%=base,z.len++;
return z;
}
Bignum operator /(Bignum &x,int y){
for (int i=x.len;~i;i--) x.v[i-1]+=x.v[i]%y*base,x.v[i]/=y;
while (x.len!=1&&!x.v[x.len]) x.len--;
while (x.v[x.len]) x.v[x.len+1]+=x.v[x.len]/base,x.v[x.len]%=base,x.len++;
return x;
}
Bignum mlt(Bignum a,int b){
Bignum res;res.init();
for (;b;b>>=1,a=a*a) if (b&1) res=res*a;
return res;
}
Bignum change(int x){
Bignum z;
while (x){
z.v[z.len-1]=x%base;
z.len++;
x/=base;
}
while (z.len!=1&&!z.v[z.len]) z.len--;
while (z.v[z.len]) z.v[z.len+1]+=z.v[z.len]/base,z.v[z.len]%=base,z.len++;
return z;
}
signed main() {
init(); Bignum ans, p;
int n = rd();
p.v[0] = 2;
for(int d = sqrt(n); d >= 1; -- d)
if(n % d == 0) {
ans = ans + mlt(p, d) * change(phi[n / d]);
if(d * d != n) ans = ans + mlt(p, n / d) * change(phi[d]);
}
ans = ans / n;
ans.write();
return 0;
}

浙公网安备 33010602011771号