[2016-3-17 Test]

Problem4:題意:有n個人站隊,個子高的會擋住格子矮(或者和他一樣高的)的,問有多少種站隊方式使得從隊頭看去恰好能看到k個人?


今天的題目感覺是水題集合OTZ,可惜木有人屠場。。


dp

我們發現如果一個一個把個子高的添加進去會出現轉移的問題

然後ORZ ymx神犇

正難則反

從大到小sort

然後發現每放入一個最小值只和他的最前面的最小值有關,如果不放在第一個的話就永遠被擋住了T^T

然後用dp[i][j][k]表示前i個人站隊然後能看到j個人,最開頭那一隻是k

然後轉移就不多說了=-=


Em,下面我們介紹一種特殊的做法:

第一類Stirling數的定義是

From百度百科

同樣第一類Stirling數同樣也可以構成一個三角,可以由此分析其性質。

  無符號Stirling數 有符號Stirling數
n=0 1 1
n=1 0 1 0 1
n=2 0 1 1 0 -1 1
n=3 0 2 3 1 0 2 -3 1
n=4 0 6 11 6 1 0 -6 11 -6 1
n=5 0 24 50 35 10 1 0 24 -50 35 -10 1
n=6 0 120 274 225 85 15 1 0 -120 274 -225 85 -15 1
n=7 0 720 1764 1624 735 175 21 1 0 720 -1764 1624 -735 175 -21 1




#include 
#include 
#include 
#include 
#define maxn 210
using namespace std;
typedef long long ll;
const ll mod = 1000000007ll;
int n, K;

ll dp[maxn][maxn][maxn];

int a[maxn];

bool cmp(const int& a, const int& b){return a > b;}

void upd(ll& a, ll b){
    a = a + b;
    if(a >= mod)a -= mod;
}

int main(){
    freopen("palace.in", "r", stdin);
    freopen("palace.out", "w", stdout);
    scanf("%d%d", &n, &K);

    for(int i = 1; i <= n; i ++)
        scanf("%d", &a[i]);

    sort(a+1, a+1+n, cmp);
    dp[1][1][1] = 1;
    for(int i = 1; i <= n; i ++){
        int now = a[i+1];
        for(int j = 1; j <= i; j ++){
            for(int k = 1; k <= i; k ++){
                if(now == a[k]){
                    upd(dp[i+1][j][i+1], dp[i][j][k]);
                    upd(dp[i+1][j][k], dp[i][j][k] * i % mod);
                }
                else{
                    upd(dp[i+1][j+1][i+1], dp[i][j][k]);
                    upd(dp[i+1][j][k], dp[i][j][k] * i % mod);
                }
            }
        }
    }
    ll ans = 0;
    for(int i = 1; i <= K; i ++)
        for(int j = 1; j <= n; j ++)
            upd(ans, dp[n][i][j]);

    printf("%lld\n", ans % mod);

	return 0;
}




Problem2 :位運算

給定N,K,L,M,求在長度爲N,每個元素在[0,2^L)的數組中,(a1 and a2)or(a2 and a3)or … or(a(n-1) and an)=K的數組有多少個

Source: CF551D


最關鍵最關鍵的是按位考慮QAQ!!!

我想了30min!!

然後就沒有然後了

喔對!!

然後你千萬不要用unsigned long long做減法

千萬不要!!


#include 
#include 
#include 
#include 

using namespace std;
typedef unsigned long long ll;
ll n, k, l, m;

struct Matrix{
    ll a[2][2];
    void clear(){memset(a, 0, sizeof a);}
    void set(){clear();a[0][0] = a[1][1] = 1;}
}mat, ans;
const int N = 2;
Matrix operator*(const Matrix& a, const Matrix& b){
    Matrix c;c.clear();
    for(int i = 0; i < N; i ++)
        for(int j = 0; j < N; j ++)
            for(int k = 0; k < N; k ++)
                c.a[i][j] = (c.a[i][j] + a.a[i][k] * b.a[k][j]) % m;
    return c;
}

ll power_mod(ll b){
    //cout << b << endl;
    mat.a[0][0] = mat.a[1][0] = mat.a[0][1] = 1;
    ans.set();
    while(b){
        if(b & 1)ans = ans * mat;
        b >>= 1;
        mat = mat * mat;
    }
    mat.clear();
    mat.a[0][1] = 1, mat.a[0][0] = 1;
    ans = mat * ans;
   // cout << ans.a[0][0] << endl;
    return ans.a[0][0];
}

ll power_mod_num(ll a, ll b){
    ll ret = 1;
    while(b){
        if(b & 1)ret = ret * a % m;
        b >>= 1;
        a = a * a % m;
    }
    return ret % m;
}

long long dcrs(long long a, long long b){
    long long t = (a - b) % (long long)m;
    if(t < 0) t += m;
    return t;
}
int main(){
    freopen("binary.in", "r", stdin);
    freopen("binary.out", "w", stdout);
    cin >> n >> k >> l >> m;
    //No Solution
    if(l == 0 && k){printf("0"); return 0;}
    //if(l == 0 && k == 0){printf("1"); return 0;}
    ll test = 1ull << l;test --;
    if(test == 0)test --;
    if(test < k){printf("0"); return 0;}
    
    //Solve
    int L = l;
    ll a0 = power_mod(n) % m;//Matrix_for_Fibonacci
    ll a1 = dcrs(power_mod_num(2, n), a0) % m;//total - Fibo
    
    ll ans = 1;
    for(int i = 1; i <= l; i ++){
        if(k & 1)ans = ans * a1 % m;
        else ans = ans * a0 % m;
        k >>= 1;
    }
    cout << ans % m << endl;
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章