Counting Sequences I(2019上海網絡賽D)(暴力dfs or 打表)

Counting Sequences I

拿着OEIS上的一個類似的序列(當時以爲是相同的)懟了半天。。。欲哭無淚

題意:問有多少長度爲nn的正整數序列滿足它們的和等於它們的積(每一位置對應相同認爲是同一序列)

思路:沒啥思路,暴力即可

  1. 首先,序列中不等於11的值不能太多,比如2122^{12}等於4096,顯然乘積增長太快了!因此大多數序列都會被剪枝掉,保證了時間複雜度很低
  2. 枚舉的過程按從大到小的方式進行枚舉,在每個位置都檢驗一遍是否後面所有數字都取11是剛好合理的
  3. 若合理,則直接使用 n!inv(i)n!*\displaystyle\sum^{取的相同數} inv(i) 計算出這些數字能產生的合法序列數

題面描述

恰好卡過去的暴力代碼

#include "bits/stdc++.h"
#define hhh printf("hhh\n")
#define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
using namespace std;
typedef long long ll;
typedef pair<int,int> pr;
inline int read() {int x=0;char c=getchar();while(c<'0'||c>'9')c=getchar();while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();return x;}

const int maxn = 1e5+10;
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
const double eps = 1e-7;

int a[30];
ll f[maxn], inv[maxn];

ll dfs(int n, int cur, int pre, int l, int r) {
	if(l+n+1-cur==r) {
		ll ans=f[n], now=1;
		for(int i=2; i<cur; ++i)
			if(a[i]==a[i-1]) now++;
			else ans=ans*inv[now]%mod, now=1;
		if(cur>1&&a[cur-1]!=1) ans=ans*inv[now]%mod*inv[n+1-cur]%mod;
		else ans=ans*inv[now+n+1-cur]%mod;
		return ans;
	}
	if(cur>n||pre==1) return 0;
	ll ans=0;
	for(int i=min(n,pre); i>=1; --i)
		if(l+i+n-cur>=r*i) a[cur]=i, ans=(ans+dfs(n,cur+1,i,l+i,r*i))%mod;
	return ans;
}

int main() {
    //ios::sync_with_stdio(false); cin.tie(0);
	f[0]=1; for(int i=1; i<=3000; ++i) f[i]=i*f[i-1]%mod;
	inv[0]=inv[1]=1;
	for(int i=2; i<=3000; ++i) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
	for(int i=2; i<=3000; ++i) inv[i]=inv[i]*inv[i-1]%mod;
    int T=read();
	while(T--) printf("%lld\n", dfs(read(),1,inf,0,1));
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章