zoukankan      html  css  js  c++  java
  • FZOJ 4109 青青草原的表彰大会

    由于博主对DP的感知能力过于低下,考试的时候竟然没发现这是DP。。。

    发现每个数一定是它前面一个数的倍数,所以这个数列一定是有序的,也不难发现这个数列最多有(O(logn))个不同的数,所以设(f[i][j])表示有(i)个不同的数,最后一个数是(j)的方案数。

    所以最后有(d)个互不相同的数的个数(cnt[d]=sum f[d][j]),然后我们考虑把这些数放到长度为(n)的题目要求的数列中,由组合数中隔板原理,可以知道有(d)种数的方案有(cnt[d] imes inom{k-1}{d-1}),所以(ans=sum_{d=1}^{log_n} cnt[d] imes inom{k-1}{d-1})

    代码如下:

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    
    using namespace std;
    
    const int N=1000009,M=1000000007;
    int n,k,a[N],ans,f[25][N],fac[N],invf[N];
    
    void init()
    {
    	scanf("%d %d",&n,&k);
    }
    
    void ADD(int &x,int y)
    {
    	x=(x+y)%M;
    }
    
    int ksm(int a,int b)
    {
    	int res=1;
    	while(b)
    	{
    		if(b&1)
    			res=1LL*res*a%M;
    		b>>=1,a=1LL*a*a%M;
    	}
    	return res;
    }
    
    void work()
    {
    	fac[0]=1;
    	int Q=N-9;
    	for (int i=1;i<=Q;i++)
    		fac[i]=1LL*fac[i-1]*i%M;
    	invf[Q]=ksm(fac[Q],M-2);
    	for (int i=Q-1;i>=0;i--)
    		invf[i]=1LL*invf[i+1]*(i+1)%M;
    	for (int i=1;i<=n;i++)
    		f[1][i]=1;
    	for (int i=1;1<<i-1<=n;i++)
    		for (int j=1;j<=n>>1;j++)
    			if(f[i][j])
    				for (int k=j+j;k<=n;k+=j)
    					ADD(f[i+1][k],f[i][j]);
    	int ans=0;
    	for (int i=1;1<<i-1<=n;i++)
    	{
    		int tmp=0;
    		for (int j=1;j<=n;j++)
    			ADD(tmp,f[i][j]);
    		ADD(ans,(int)(1LL*tmp*fac[k-1]%M*invf[i-1]%M*invf[k-i]%M));
    	}
    	printf("%d
    ",ans);
    }
    
    int main()
    {
    	init();
    	work();
    	return 0;
    }
    
    由于博主比较菜,所以有很多东西待学习,大部分文章会持续更新,另外如果有出错或者不周之处,欢迎大家在评论中指出!
  • 相关阅读:
    BUAA OO Unit1 表达式求导
    中介者模式
    命令模式
    观察者模式
    解释器模式
    策略模式
    迭代器模式
    模板方法模式
    代理模式
    桥接模式
  • 原文地址:https://www.cnblogs.com/With-penguin/p/12707496.html
Copyright © 2011-2022 走看看