• 题解 CF1103E Radix sum


    题目传送门

    题目大意

    给出一个(n)个数的序列(a_{1,2,..,n}),可以选(n)次,每次可以选与上次选的相同的数,问对于(forall pin[0,n-1])满足选出来的数进行十进制不进位加法结果为(p)的方案数。答案对(2^{58})取模。

    思路

    乍一看,这是一道(k=10)(k)进制( ext {FWT})的板题。但是,我们发现这个模数十分的神仙,于是我们就需要解决下面两个问题:

    • 如何求出(10^5)的逆元

    • 如何求出模(2^{58})意义下的(w_{10})

    似乎第一个问题比较好解决一点。这里解释一下为什么是除以(10^5),本来逆运算的时候应该除以(10),但是我们为了方便可以先不除,最后一起除。

    我们发现(5)在模(2^{58})意义下是有逆元的,于是我们的问题就是如何求出(2^5)的逆元。我们可以先求出模(2^{64})下的答案,然后我们发现直接除以(2^5)就是答案了。

    于是,我们发现模(2^{64})其实就是( ext {unsigned long long})自然溢出。

    我们现在需要解决第二个问题。我们发现这个无理数不可能在(2^{58})有对应的数。而我们现在又发现(w_{10}^5=w_2=-1)(2^{64}),于是,我们可以设(x=w_{10}),于是我们可以用多项式来表示,最后的答案就是对(x^5+1)取模。

    于是我们只需要考虑如何把一个多项式转换成整数。我们发现模(x^5+1)实际上就等价于模(1-x+x^2-x^3+x^4)。而我们发现最后的答案其实就是常数项。

    于是,我们就在(Theta(2500nlog n))的时间复杂度解决了这个问题。

    细节

    • (forall 5le ale 8,x^aequiv -x^{amod 5}(mod x^5+1))

    • ([x^0](a_0x^0+a_1x^1+a_2x^2+a_3x^3+a_4x^4)equiv a_0-a_1(mod 1-x+x^2-x^3+x^4))

    ( ext {Code})

    #include <bits/stdc++.h>
    using namespace std;
    
    #define ull unsigned long long
    #define Int register int
    #define MAXN 400005
    #define lim 100000
    
    template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
    template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
    template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
    
    int n;
    ull inv = 6723469279985657373ull;
    
    struct Poly{
    	ull a[5];
    	Poly(){a[0] = a[1] = a[2] = a[3] = a[4] = 0;}
    	Poly operator + (Poly p){
    		Poly res;
    		for (Int i = 0;i < 5;++ i) res.a[i] = a[i] + p.a[i];
    		return res;
    	}
    	Poly operator * (Poly p){
    		ull tmp[10];Poly res;
    		memset (tmp,0,sizeof (tmp));
    		for (Int i = 0;i < 5;++ i)
    			for (Int j = 0;j < 5;++ j)
    				tmp[i + j] += a[i] * p.a[j];
    		for (Int i = 0;i < 5;++ i) res.a[i] = tmp[i] - tmp[i + 5];
    		return res; 
    	}
    	ull Turn (){
    		ull tmp = a[1];for (Int i = 0;i < 5;++ i) a[i] -= tmp;
    		tmp = a[2];for (Int i = 0;i < 5;i += 2) a[i] -= tmp;
    		return a[0];
    	}
    }ans[MAXN],bas[10],zero;
    
    Poly quick_pow (Poly a,int b){
    	Poly res;memset (res.a,0,sizeof (res.a)),res.a[0] = 1;
    	for (;b;b >>= 1,a = a * a) if (b & 1) res = res * a;
    	return res;
    }
    
    void FWT (Poly *a,int type){
    	int id[10];Poly b[10];
    	for (Int len = 1;len < lim;len *= 10)
    		for (Int i = 0;i < lim;i += len * 10)
    			for (Int j = 0;j < len;++ j){
    				for (Int d = 0;d < 10;++ d){
    					id[d] = i + j + d * len;
    					b[d] = a[id[d]],a[id[d]] = zero;
    				}
    				for (Int d = 0;d < 10;++ d)
    					for (Int e = 0;e < 10;++ e)
    						a[id[d]] = a[id[d]] + bas[(10 + type) * d * e % 10] * b[e];
    			}
    }
    
    signed main(){
    	read (n);
    	for (Int i = 1,a;i <= n;++ i) read (a),++ ans[a].a[0];
    	for (Int i = 0;i < 10;++ i) bas[i].a[i % 5] = i >= 5 ? -1 : 1;
    	FWT (ans,1);
    	for (Int i = 0;i < lim;++ i) ans[i] = quick_pow (ans[i],n);
    	FWT (ans,-1);
    	for (Int i = 0;i < n;++ i) write (((ans[i].Turn() * inv) >> 5) % (1ull << 58)),putchar ('
    ');
    	return 0;
    }
    

    参考博客

    https://www.luogu.com.cn/blog/foreverlasting/solution-cf1103e

    https://www.cnblogs.com/Mr-Spade/p/10390667.html
    https://memset0.cn/cf1103e

    https://www.luogu.com.cn/blog/command-block/wei-yun-suan-juan-ji-yu-ji-kuo-zhan

  • 相关阅读:
    什么是shell
    Jenkins+python+selenium持续继承自动化测试
    selenium+python自动化
    产品和项目的概念
    继承与派生:赋值兼容规则(转)
    继承与派生:虚基类及其派生类的构造函数(转)
    重载函数与函数模板(转)
    继承与派生:作用域分辨符(转)
    作用域和可见性(转)
    继承与派生:派生类的析构函数(转)
  • 原文地址:https://www.cnblogs.com/Dark-Romance/p/13266284.html
Copyright © 2020-2023  润新知