题目大意

  有一个 \(n\) 个点的环,你要用 \(m\) 中颜色染这 \(n\) 个点。

  要求连续 \(m\) 个点的颜色不能是 $1 \sim m $ 的排列。

  两种环相同当且仅当这两个环可以在旋转之后变得一模一样。

  求方案数对 \({10}^9+7\) 取模的结果。

  \(n\leq {10}^9,m\leq 7\)

题解

  考虑 polya 定理,记 \(f(n)\) 为 \(n\) 个点的答案,\(g(n)\) 为 \(n\) 个点不考虑旋转的答案。那么就有

\[\begin{align}
f(n)&=\frac{1}{n}\sum_{i=1}^ng(\gcd(n,i))\\
&=\frac{1}{n}\sum_{i\mid n}\varphi(\frac{n}{i})g(i)
\end{align}
\]

  \(g(i)\) 可以 DP 计算。

  记 \(h_{i,j,k}\) 为长度为 \(i\) 的链,前 \(m\) 个点的状态(颜色)为 \(j\),最后 \(m\) 个点的状态为 \(k\) 的方案数。

  还可以记录前 \(m\) 个颜色的前多少个是互不相同的,还有最后 \(m\) 个点的颜色。就前 \(j\) 个的颜色是互不相同的,第 \(j+1\) 个点颜色和前面某个点颜色相同。

  显然 \(g(i)\) 有一个长度不超过 \(m^m\) 的递推式。

  暴力打出前面的项然后 BM 求出递推式即可。

  开 O2 只用了 48s 就打出来了。

  \(m=7\) 时递推式长度为 \(409\)。

  表在这:https://github.com/ywwywwyww/THUSC2017/tree/master/yww/farben

代码

const int N=1010;
const ll p=1000000007;
ll fp(ll a,ll b)
{
ll s=1;
for(;b;b>>=1,a=a*a%p)
if(b&1)
s=s*a%p;
return s;
} ll b[10][2010]=表;
ll a[10][2010]=表; int c[N],d[N],t;
ll pw[N][N];
ll ans;
int n,m;
int s[N];
int len;
void add(int &a,ll b)
{
a=(a+b)%p;
} void mul()
{
static int f[N];
for(int i=0;i<=2*len;i++)
f[i]=0;
for(int i=0;i<=len;i++)
if(s[i])
for(int j=0;j<=len;j++)
add(f[i+j],(ll)s[i]*s[j]);
for(int i=0;i<=2*len;i++)
s[i]=f[i];
}
void module()
{
for(int i=2*len;i>=len;i--)
if(s[i])
{
for(int j=1;j<=len;j++)
add(s[i-j],(ll)s[i]*b[m][j]);
s[i]=0;
}
} void fp(int x)
{
if(!x)
{
for(int i=0;i<=2*len;i++)
s[i]=0;
s[0]=1;
return;
}
fp(x>>1);
mul();
if(x&1)
{
for(int i=2*len;i>=1;i--)
s[i]=s[i-1];
s[0]=0;
}
module();
} ll calc(int x)
{
if(x<=500)
return a[m][x];
fp(x-1);
ll res=0;
for(int i=1;i<=len;i++)
res=(res+(ll)a[m][i]*s[i-1])%p;
return res;
} void dfs(int x,int y,ll phi)
{
if(x>t)
{
ans=(ans+calc(y)*phi)%p;
return;
}
for(int i=0;i<d[x];i++)
dfs(x+1,y*pw[x][i],phi*(c[x]-1)%p*pw[x][d[x]-i-1]%p);
dfs(x+1,y*pw[x][d[x]],phi);
}
int main()
{
open("farben");
scanf("%d%d",&n,&m);
int _n=n;
for(int i=2;i*i<=_n;i++)
if(_n%i==0)
{
c[++t]=i;
while(_n%i==0)
{
d[t]++;
_n/=i;
}
}
if(_n>1)
{
c[++t]=_n;
d[t]=1;
}
for(int i=1;i<=t;i++)
{
pw[i][0]=1;
for(int j=1;j<=d[i];j++)
pw[i][j]=pw[i][j-1]*c[i]%p;
}
len=b[m][0];
dfs(1,1,1);
ans=ans*fp(n,p-2)%p;
ans=(ans%p+p)%p;
printf("%lld\n",ans);
return 0;
}

打表程序

const ll p=1000000007;
const int N=1010;
const int n=1000;
//const int m=5;
int m; ll fp(ll a,ll b)
{
ll s=1;
for(;b;b>>=1,a=a*a%p)
if(b&1)
s=s*a%p;
return s;
} const int MA=2100000; int e[MA];
int ban[MA];
vector<int> g[N];
int pw[N];
int ma; namespace gao1
{
int a[N],b[N],c[N];
void dfs(int x)
{
if(x>m)
{
for(int i=1;i<=m;i++)
b[i]=0;
int tot=0;
int s=0;
int s2=0;
int first=0;
for(int i=1;i<=m;i++)
{
if(!b[a[i]])
b[a[i]]=++tot;
c[i]=b[a[i]];
s+=c[i]*pw[i-1];
s2+=a[i]*pw[i-1];
if(c[i]<=c[i-1]&&!first)
first=i-1;
}
if(tot==m)
ban[s2]=1;
else
g[first].push_back(s);
return;
}
for(int i=1;i<=m;i++)
{
a[x]=i;
dfs(x+1);
}
}
void gao()
{
dfs(1);
}
} namespace gao2
{
int a[N],b[N],c[N];
void dfs(int x)
{
if(x>m)
{
for(int i=1;i<=m;i++)
b[i]=0;
for(int i=m;i>=1;i--)
if(!a[i]||!b[a[i]])
{
c[i]=a[i];
b[a[i]]=1;
}
else
c[i]=0;
int s=0,s1=0;
for(int i=1;i<=m;i++)
s+=c[i]*pw[i-1];
for(int i=1;i<=m;i++)
s1+=a[i]*pw[i-1];
e[s1]=s;
return;
}
for(int i=0;i<=m;i++)
{
a[x]=i;
dfs(x+1);
}
}
void gao()
{
dfs(1);
}
} int f[N];
int h[2][MA];
int d[MA]; void add(int &a,int b)
{
a=(a+b)%p;
} int append(int a,int b)
{
return a/(m+1)+b*pw[m-1];
} namespace gao3
{
void gao(int x)
{
memset(d,0,sizeof d); for(int i=0;i<=ma;i++)
{
int flag=1;
for(int y=i,j=1;j<=x;j++)
{
y=append(y,j);
if(ban[y])
{
flag=0;
break;
}
}
d[i]=flag;
} memset(h,0,sizeof h);
int cur=0;
for(auto v:g[x])
h[cur][e[v]]++;
for(int i=m;i<=n;i++)
{
fprintf(stderr,"%d %d %d\n",m,x,i);
memset(h[cur^1],0,sizeof h[cur^1]);
for(int j=0;j<=ma;j++)
if(h[cur][j]&&!ban[j])
{
add(f[i],d[j]*h[cur][j]);
for(int k=1;k<=m;k++)
add(h[cur^1][e[append(j,k)]],h[cur][j]);
}
cur^=1;
}
}
} int main(int argc,char **argv)
{
// freopen("farben2.txt","w",stdout);
sscanf(argv[1],"%d",&m);
ma=fp(m+1,m);
pw[0]=1;
for(int i=1;i<=m;i++)
pw[i]=pw[i-1]*(m+1);
gao1::gao();
gao2::gao(); for(int i=1;i<m;i++)
f[i]=fp(m,i); for(int i=1;i<m;i++)
gao3::gao(i); for(int i=1;i<=n;i++)
printf("%d\n",f[i]);
return 0;
}

【THUSC2017】【LOJ2981】如果奇迹有颜色 DP BM 打表 线性递推的更多相关文章

  1. 【模板】BM + CH(线性递推式的求解,常系数齐次线性递推)

    这里所有的内容都将有关于一个线性递推: $f_{n} = \sum\limits_{i = 1}^{k} a_{i} * f_{n - i}$,其中$f_{0}, f_{1}, ... , f_{k ...

  2. HDU 5863 cjj's string game ( 16年多校10 G 题、矩阵快速幂优化线性递推DP )

    题目链接 题意 : 有种不同的字符,每种字符有无限个,要求用这k种字符构造两个长度为n的字符串a和b,使得a串和b串的最长公共部分长度恰为m,问方案数 分析 : 直觉是DP 不过当时看到 n 很大.但 ...

  3. HDU - 6172:Array Challenge (BM线性递推)

    题意:给出,三个函数,h,b,a,然后T次询问,每次给出n,求sqrt(an); 思路:不会推,但是感觉a应该是线性的,这个时候我们就可以用BM线性递推,自己求出前几项,然后放到模板里,就可以求了. ...

  4. BM求线性递推模板(杜教版)

    BM求线性递推模板(杜教版) BM求线性递推是最近了解到的一个黑科技 如果一个数列.其能够通过线性递推而来 例如使用矩阵快速幂优化的 DP 大概都可以丢进去 则使用 BM 即可得到任意 N 项的数列元 ...

  5. [NOI2017]泳池——概率DP+线性递推

    [NOI2017]泳池 实在没有思路啊~~~ luogu题解 1.差分,转化成至多k的概率减去至多k-1的概率.这样就不用记录“有没有出现k”这个信息了 2.n是1e9,感觉要递推然后利用数列的加速技 ...

  6. LG5487 【模板】线性递推+BM算法

    [模板]线性递推+BM算法 给出一个数列 \(P\) 从 \(0\) 开始的前 \(n\) 项,求序列 \(P\) 在\(\bmod~998244353\) 下的最短线性递推式,并在 \(\bmod~ ...

  7. 2018 焦作网络赛 L Poor God Water ( AC自动机构造矩阵、BM求线性递推、手动构造矩阵、矩阵快速幂 )

    题目链接 题意 : 实际上可以转化一下题意 要求求出用三个不同元素的字符集例如 { 'A' .'B' .'C' } 构造出长度为 n 且不包含 AAA.BBB CCC.ACB BCA.CAC CBC ...

  8. 牛客多校第九场 A The power of Fibonacci 杜教bm解线性递推

    题意:计算斐波那契数列前n项和的m次方模1e9 题解: $F[i] – F[i-1] – F[i-2] = 0$ $F[i]^2 – 2 F[i-1]^2 – 2 F[i-2]^2 + F[i-3] ...

  9. 【CF607B】Zuma——区间dp(记忆化搜索/递推)

    以下是从中文翻译成人话的题面: 给定一个长度小于等于500的序列,每个数字代表一个颜色,每次可以消掉一个回文串,问最多消几次可以消完? (7.16) 这个题从洛谷pend回来以后显示有103个测试点( ...

随机推荐

  1. windows环境设置mysql自动备份(测试成功)

    00.背景介绍 最近做了个小程序,使用的是mysql数据库,涉及到将程序数据备份的事:虽然大部分数据库客户端工具都具有备份功能,但并不能做到定期自动备份:在Windows环境下,手工备份MySQL是很 ...

  2. C# 曲线上的点(一) 获取指定横坐标对应的纵坐标值

    获取直线上的点,很容易,那曲线呢?二阶贝塞尔.三阶贝塞尔.多段混合曲线,如何获取指定横坐标对应的纵坐标? 如下图形: 实现方案 曲线上的点集 Geometry提供了一个函数GetFlattenedPa ...

  3. C# 添加枚举中文资源

    在业务开发过程中,添加枚举,在固定枚举值的同时,也需要中文的文案. 如果不想添加语言资源项.添加枚举转语资源项,可以使用特性标记. 属性描述 DescriptionAttribute 先看案例: pu ...

  4. (五) Keras Adam优化器以及CNN应用于手写识别

    视频学习来源 https://www.bilibili.com/video/av40787141?from=search&seid=17003307842787199553 笔记 Adam,常 ...

  5. Android项目实战(四十五):Zxing二维码切换横屏扫描

    Demo链接 默认是竖屏扫描,但是当我们在清单文件中配置横屏显示的时候: <activity android:name=".CaptureActivity" android: ...

  6. TCP点对点转发的实现与原理(nodejs)

    Nagent Nagent是TCP点对点转发实现,名称来源于Nat与Agent的组合.类似frp项目,可以在局域网与互联网提供桥梁. 前提是你要有一台流量服务器并且有一个公网IP.如果没有,也可以找服 ...

  7. Linux下LANMP集成环境中编译增加pdo_odbc模块

    linux版本为CentOs6.5,php集成环境为lanmp_v3.1,集成环境中默认的pdo扩展为:mysql, sqlite, sqlite2,现在有需求想链接微软的Access数据库,所以需要 ...

  8. MongoDB自学(2)

    条件操作符: gt(大于),gte(大于等于),lt(小于),lte(小于等于)E.G:db.People.find({age:{$gt:100}})//查找集合里age大于100的文档 注意:str ...

  9. selenium-webdriver的二次封装(十)

    接着上篇随笔 selenium-配置文件定位元素 ,进行了配置文件设置后,将配置文件运用到定位元素中 思路:拿到定位的 key 和 value 后,对 webdrvier 中定位进行封装,使可以直接运 ...

  10. 微软与开源干货对比篇_PHP和 ASP.NET在 Session实现和管理机制上差异

    微软与开源干货对比篇_PHP和 ASP.NET在 Session实现和管理机制上差异 前言:由于开发人员要靠工具吃饭,可能和开发工具.语言.环境呆的时间比和老婆孩子亲人在一起的时间还多,所以每个人或多 ...