洛谷 P4317 花神的数论题

    xiaoxiao2023-11-01  27

    233

    题目:题意:分析:代码:


    题目:

    传送门


    题意:

    给出一个正整数 n n n ,问你 ∏ i = 1 N s u m ( i ) \prod_{i=1}^{N}sum(i) i=1Nsum(i) p . s . s u m ( i ) p.s. sum(i) p.s.sum(i) i i i在二进制下时 1 1 1的个数


    分析:

    对于数 n n n来说,必定是 1 — n 1—n 1n中最大的这不废话吗 因此,可以有两个引理: 1. 1. 1.在二进制下 t a ta ta的首位 1 1 1一定是出现最早的 2. 2. 2.首位 1 1 1出现的位置后都必定存在 1 1 1 证明: 1. 1. 1.因为 n n n是最大的,所以显然(逃 2. 2. 2.假设 n n n 4 4 4,,则在二进制下为 1000 1000 1000,因为我们要求的是 1 — n 1—n 1n。所以必定存在一个恰好比 n n n少一位并且所有位上的都是 1 1 1,我们成为 s u p e r super super n u m b e r number number。在这个例子中, s u p e r   n u m b e r super\ number super number 3 3 3,即 111 111 111 根据 引 理 1 引理1 1,我们得到了需要倒序求解的思路 ( n 2 表 示 (n_2表示 (n2n 的 二 进 制 数 ) 的二进制数) ) 根据 引 理 2 引理2 2,我们知道的当 n 2 n_2 n2出现 1 1 1后,之后便可以直接累加 用人话来说,设 f i f_i fi 1 1 1出现次数恰好为 i i i时的方案数(雾不知道怎么正确表达) 随后我们可以得到一个式子: ∑ i = n 1 f [ i ] + = f [ i − 1 ] ( 其 实 不 需 要 ∑ , 只 是 觉 得 这 样 表 示 循 环 比 较 高 级 233 ) \sum_{i=n}^1f[i]+=f[i-1](其实不需要\sum,只是觉得这样表示循环比较高级233) i=n1f[i]+=f[i1](233) 也就是上文说到的累加,当我们遍历多一位时, 1 1 1出现的次数便必然会 + 1 +1 +1 P . S . P.S. P.S.因为我们不能保证 n n n一定是 s u p e r   n u m b e r super\ number super number,所以统计 1 1 1出现的次数时从 0 0 0开始统计,最后再补上一次便不会漏记,且因为我们补得是最后一位,所以不用再进行累加


    代码:

    // luogu-judger-enable-o2 #include<cstdio> #include<string> #include<cstring> #include<iostream> #include<algorithm> #include<queue> #define LL long long #define LZX 10000007 inline LL read() { LL d=0,f=1;char s=getchar(); while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();} while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();} return d*f; } using namespace std; LL ksm(LL x,LL y) { LL s=1; while(y) { if(y%2) (s*=x)%=LZX; y/=2;(x*=x)%=LZX; } return s; } LL f[55],cnt=0; int main() { LL n=read(); for(LL j=49;~j;j--) { for(LL i=49;i;i--) f[i]+=f[i-1]; if(n>>j&1) f[cnt++]++; } f[cnt]++; LL ans=1; for(LL i=1;i<=49;i++) (ans*=ksm(i,f[i]))%=LZX; cout<<ans; return 0; }
    最新回复(0)