AGC 047 C 题解

89 篇文章 1 订阅

AGC 047 C 题解

一个数论好题

可以发现P是一个NTT模数,原根是2。

则任何一个<P的数都可以表示成 2 x m o d    p 2^x\mod p 2xmodp

两个数相乘也就可以表示成 2 x × 2 y = 2 ( x + y ) m o d    ( p − 1 ) 2^x\times 2^y=2^{(x+y)\mod (p-1)} 2x×2y=2(x+y)mod(p1)

直接fft就好了。

/*
{
######################
#       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;
/*}
*/
typedef complex<double> Comp;
const double PI=3.14159265358979323846;
const Comp I(0,1);
const int len=1<<19;
int rev[len];
void butterfly(vector<Comp> & v){
	rep(i,len){
		rev[i]=rev[i>>1]>>1;
		if(i&1) rev[i]|=len>>1; 
	}
	rep(i,len) if(rev[i]>i) swap(v[i],v[rev[i]]);
}
vector<Comp> fft(vector<Comp> v,int ty){
	butterfly(v);
	vector<Comp> nex;
	for(int l=2;l<=len;l<<=1){
		nex.clear();
		nex.resize(len);
		Comp step(cos(2.0*PI/l),sin(2.0*ty*PI/l));
		for(int j=0;j<len;j+=l){
			Comp now(1,0);
			for(int k=0;k<l/2;++k){
				Comp A,B;
				A=v[j+k];
				B=v[j+l/2+k];
				B=now*B;
				nex[j+k]=A+B;
				nex[j+k+l/2]=A-B;
				now=now*step;
			}
		}
		v=nex;
	}
	return v;
}
const int MOD=200003;
const int g=2;
int is[MOD],pow_[MOD];
vector<Comp> v(len);
LL cnt[len];
int main(){
	int now=1;
	rb(i,0,MOD-2){
		is[now]=i;
		pow_[i]=now;
		now<<=1;
		now%=MOD;
	}
	vector<int> a;
	LL rest=0;
	int n;
	scanf("%d",&n);
	rb(i,1,n){
		int ai;
		scanf("%d",&ai);
		if(ai){
			a.PB(ai);
			cnt[is[ai]]++;
		}
	}
	n=a.size();
	rep(i,len) v[i]=Comp(cnt[i],0);
	v=fft(v,1);
	rep(i,len) v[i]*=v[i];
	v=fft(v,-1);
	rep(i,len) cnt[i]=floor((v[i].real()/len)+0.5);
	rb(i,0,MOD-2){
		cnt[i]+=cnt[i+MOD-1];
		rest+=1ll*pow_[i]*cnt[i];
	}
	rep(i,n)
		rest-=1ll*a[i]*a[i]%MOD;
	cout<<rest/2<<endl;
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值