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;
}

posted @ 2021-07-21 22:05  wlhp  阅读(28)  评论(0)    收藏  举报