无题3

第一题:

插板法,多思考一下应该出得来;

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod = 998244353;
const int M = 1000005;
ll dp[M], fac[M], a[M], vfac[M], sum[M];
ll ksm(ll a, ll b){
    ll ret=1;
    for(;b;b>>=1,a=a*a%mod)
    if(b&1) ret=ret*a%mod;
    return ret;
}

inline ll ni(ll a){
    return ksm(a, mod - 2);
}

int main(){
    freopen("qiang.in","r",stdin);
    freopen("qiang.out","w",stdout);
    int n;
    scanf("%d", &n); 
    fac[0] = vfac[0] = 1;
    
    dp[1] = 1;
    int x;
    for(int i = 1; i <= n; i++){
        scanf("%d", &a[i]);
        sum[i] = sum[i - 1] + a[i];
    }
    for(int i = 1; i <= sum[n]; i++) fac[i] = fac[i - 1] * 1LL*i % mod, vfac[i] = ni(fac[i]);
    for(int i = 2; i <= n; i++){
        dp[i] = dp[i - 1] * fac[sum[i] - 1] % mod * vfac[a[i] - 1] % mod * vfac[sum[i - 1]] % mod;
    }
    printf("%lld\n",dp[n]);
}
View Code

 

第二题:矩阵块速幂,又听zyy大佬讲了一遍,讲的太好了;

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int M = (1<<4) + 2;
int n; ll mod;
inline ll moc(int a){return a >= mod ? a - mod : a;}
struct Maxtri{
    ll w[M][M];
    void unit(){
        for(int i = 0; i < M; i++)
            for(int j = 0; j < M; j++)
                w[i][j] = (i == j);
    }
    void init(){
        for(int i = 0; i < M; i++)
            for(int j = 0; j < M; j++)
                w[i][j] = 0;
    }
    void print(){
        for(int i = 0; i < M; i++){
            for(int j = 0; j < M; j++)printf("%d ", w[i][j]);puts("");
        }
            
    }
    
}tr;

Maxtri  operator *(const  Maxtri &s, const  Maxtri &t){
    Maxtri a;
    for(int i = 0; i < M; i++)
        for(int j = 0; j < M; j++){
            a.w[i][j] = 0;
            for(int k = 0; k < M; k++)
                a.w[i][j] = moc(a.w[i][j] + s.w[i][k] * t.w[k][j] % mod);
        }
    return a;
            
}

Maxtri ksm(Maxtri a, int b){
    Maxtri ret;
    for(ret.unit(); b; b >>= 1, a=a*a)
        if(b & 1) ret = ret * a;
    return ret;
}

void dfs(int dep, int os, int ns){
    if(!dep) {
        tr.w[ns][os] = 1;
        return ;
    }
    if((1<<(dep-1))&os){
        dfs(dep - 1, os, ns);
        if(dep - 1 > 0 && ((1<<(dep-2))&os)) dfs(dep - 2, os, ns + (1<<(dep-1)) + (1<<(dep-2)));
    }
    else dfs(dep - 1, os, ns + (1<<(dep-1)));
}


int main(){
    freopen("count.in","r",stdin);
    freopen("count.out","w",stdout);
    int n;
    for(int i = 0; i < (1<<4); i++)
    dfs(4, i, 0);
    while(scanf("%d%lld", &n, &mod) == 2 && n && mod){
        Maxtri rec;
        rec.init();
        rec.w[(1<<4)-1][0] = 1;
        Maxtri ans = ksm(tr, n);
        //ans.print();
        ll res = ans.w[(1<<4)-1][(1<<4)-1];        
        printf("%lld\n", res);    
    }
    
}
View Code

 

第三题:先AB差分得到操作次数的数字,维护一个单调不降的数组,那么操作次数一定是第一个数;

怎么维护单降序列:如果后面凸起来,  1.重开一个新的, 2.接在原来的线上,我们就需要额外操作;

额外操作:(a[i] - a[i - 1] + 4) % 4, 使得当前操作次数不小于上一次操作次数;(相当于把新的填平了);

不论合不合法都记录额外操作,当不合法时,选取之前最小的代价,使每一步最优;

eg: 差分后数组

#include<bits/stdc++.h>
using namespace std;
const int M = 100005;
int a[M], b[M], s[15];

int main(){
    freopen("sequence.in","r",stdin);
    freopen("sequence.out","w",stdout);
    int T;
    scanf("%d", &T);
    while(T--){
        memset(s, 0, sizeof(s));
        int n;
        scanf("%d", &n);
        for(int i = 1; i <= n; i++)scanf("%d", &a[i]);
        for(int i = 1; i <= n; i++)scanf("%d", &b[i]), a[i] = (b[i] - a[i] + 4) % 4;
        int ans = a[1];
        for(int i = 2; i <= n; i++){
            s[(a[i] - a[i - 1] + 4) % 4]++;
            if(a[i - 1] >= a[i])continue;
            int j;
            for(j=1;!s[j];j++);
            s[j]--;
            ans += j;
        }
        printf("%d\n",ans);    
    }
    
} 
View Code

 

posted @ 2018-09-19 16:38  Ed_Sheeran  阅读(140)  评论(0编辑  收藏  举报