CF1957E Carousel of Combinations

Carousel of Combinations

题目链接

Problem

求:i=1nj=1i(F(i,j)modj)

其中 F(i,j) 表示从 i 个数当中选 j 个的不同圆排列数。

最终答案对 109+7 取模。

注意区分题目中的两个取模的位置。

数据范围:t105n106

Sol

首先 F(i,j)=i!(ij)!j=(ij)(j1)!。然后 (j1)!modj 只有在 j 是素数或者 j=4 的时候值不为 0j=4 的时候可以单独算。当 jprime 的时候,F(i,j)=(ij)modj=(i/jj/j)×(imodjjmodj)=ij。现在要求 pprime((i=1nip)modp)。这个东西直接做是会 T 的,但是 ip 的总的断点个数是 O(nlnlnn) 的。考虑对这个东西直接线性筛,枚举质数 p,然后就是做 np 段区间加。这里可以直接差分,最后跑一遍前缀和即可。

Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define fi first
#define se second
const int mod = 1e9 + 7;
int vis[1000005], prC, pri[1000005];
ll ans[1000005];
void Init(int n = 1e6) {
   for (int i = 2; i <= n; ++i) {
   	if (!vis[i]) pri[++prC] = i;
   	for (int j = 1; j <= prC && i * pri[j] <= n; ++j) {
   		vis[i * pri[j]] = 1;
   		if (i % pri[j] == 0) break;
   	}
   }
   vis[4] = 0;
   for (int i = 2; i <= n; ++i) {
   	if (vis[i]) continue;
   	ll t = i == 4 ? 2 : i - 1;
   	for (int j = 1, k = i; k <= n; ++j, k += i) {
   		ll w = j * t % i;
   		(ans[k] += w) %= mod;
   		if (k + i <= n) (ans[k + i] -= w) %= mod;
   	}
   }
   for (int i = 1; i <= n; ++i) (ans[i] += ans[i - 1] + mod) %= mod;
   for (int i = 1; i <= n; ++i) (ans[i] += ans[i - 1] + mod) %= mod;
}
int n;
void Solve() {
   scanf("%d", &n);
   printf("%lld\n", ans[n]);
}
int main() {
   Init();
   int T;
   scanf("%d", &T);
   while (T--)
   	Solve();
   return 0;
}
posted @   Pengzt  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示