SRM585 Div1

コーナーケース氏死んでくれ〜〜 ちゃんと制約読もう

easy
まあ色んな方法あるが自分は下から取っていくイメージ

#define MOD (1000000007LL)
ll p[1000010];
ll r[1000010];

class TrafficCongestion{
    public:
	int theMinCars(int treeHeight){
	    int h = treeHeight;
	    p[0] = 1LL; p[1] = 2LL;
	    for(int i = 2; i <= 1000000; ++i) p[i] = p[i-1] * 2LL % MOD;

	    if(h == 0) return 1;
	    if(h == 1) return 1;
	    
	    r[0] = 1;
	    r[1] = 1;
	    for(int i = 2; i <= h; ++i) r[i] = (p[i-1] + r[i-2]) % MOD;
	    
	    return (int)r[h];
	}
};

med
自明にdpだが式が少し難しい。左から見ていって、新しい数をそれまであった列に挿入していくイメージで考えると、strictly increasingな末尾に挿入すればLISnumberがそのままで、そうでない所に挿入すれば+1されることに気付くと、よくある数え上げdpになる。

#define MOD (1000000007LL)

int n;
ll comb[1310][1310];
ll dp[40][1310];

void pre(){
    comb[0][0] = 1LL;
    comb[1][0] = comb[1][1] = 1;
    for(int i = 2; i <= 1300; ++i){
	comb[i][0] = comb[i][i] = 1;
	for(int j = 1; j < i; ++j) comb[i][j] = (comb[i-1][j-1] + comb[i-1][j]) % MOD; 
    }
}

class LISNumber{
    public:
	int count(vector <int> cardsnum, int K){
	    vector<int> a = cardsnum;
	    n = (int)a.size();
	    pre();
	    
	    int s = a[0];
	    dp[1][a[0]] = 1;
	    
	    for(int i = 1; i < n; ++i){		
		s += a[i];
		for(int j = 1; j <= s; ++j){
		    for(int k = max(1, j - a[i]); k <= min(j, s); ++k){
			if(a[i] + k - j < 0 || a[i] - j > 1) continue;
			dp[i+1][j] += (dp[i][k] * comb[k][a[i] + k - j]) % MOD * comb[s - k][j - k];
			dp[i+1][j] %= MOD;
		    }
		}
	    }
	    
	    return (int)dp[n][K];    
	}
};