TopCoder SRM 684 Div1 600 DivFree

53 篇文章 0 订阅
27 篇文章 0 订阅

UPD:感觉这个应该不叫容斥原理…
又是一道神奇的题

最开始就想到容斥,结果写完了之后过不了样例,意识到我那个容斥好像并不满足容斥那个组合数的条件。。

然后标算的容斥刷新了我对容斥的认识= =

先预处理出 d p [ i ] dp[i] dp[i],表示长度为 i i i的不合法序列数( d p [ 1 ] dp[1] dp[1]事实上是合法的,但还是把它算出来),这里说的不合法是指每对相邻元素都不合法,即每个数都整除它前一个数(其实前后都无所谓啦)。
我们用 h [ i ] h[i] h[i]表示长度为 i i i的合法序列个数,考虑我们在 h [ i − 1 ] h[i-1] h[i1]最后再加一个数,总方案数为 h [ i − 1 ] × d p [ 1 ] h[i-1]×dp[1] h[i1]×dp[1],但这个数可能整除前一个数,我们们把这些情况减去,就是 − h [ i − 2 ] × d p [ 2 ] -h[i-2]×dp[2] h[i2]×dp[2],然后会发现,好像会把后三个数不合法的情况多减,所以又 + h [ i − 3 ] × d p [ 3 ] +h[i-3]×dp[3] +h[i3]×dp[3]…好吧,感觉我好像没怎么讲清楚,语言表达能力有限,最好手模一下。

代码很好懂。

#include <bits/stdc++.h>
#define ll long long
#define fr(i,x,y) for(int i=x;i<=y;i++)
#define rf(i,x,y) for(int i=x;i>=y;i--)
using namespace std;
const int p=1e9+7;
const int N=50001;
const int Lg=17;
int f[N][Lg],dp[Lg];
ll h[N];

template<class T> void checkmin(T &a,const T &b) { if (b<a) a=b; } 
template<class T> void checkmax(T &a,const T &b) { if (b>a) a=b; }

class DivFree {
public:
    int dfcount( int n, int k ) ;
};

void Add(int &x,int y){
	x+=y;
	while(x<0) x+=p;
	while(x>=p) x-=p;
}

void Add(ll &x,ll y){
	x+=y;
	while(x<0) x+=p;
	while(x>=p) x-=p;
}

int DivFree::dfcount(int n, int K) {
	//init(K);
	fr(i,1,K) f[i][1]=1;
	for(int j=1;j<Lg;j++)
	 for(int i=1;i<=K;i++)
	  if (f[i][j]){
	  	for(int k=2*i;k<=K;k+=i)
	  	 Add(f[k][j+1],f[i][j]);
	  	Add(dp[j],f[i][j]);
	  }
	h[0]=1;
	fr(i,1,n)
	 for(int j=1,v=1;j<Lg&&j<=i;j++,v=-v)
	  Add(h[i],v*h[i-j]*dp[j]%p);
	return h[n];
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值