码迷,mamicode.com
首页 > 其他好文 > 详细

18.9.18 考试总结

时间:2018-09-18 19:03:20      阅读:189      评论:0      收藏:0      [点我收藏+]

标签:表示   lin   mic   http   void   open   怎么办   付出   ...   

状态不好怎么办呢

今天考试我服了 第一题很简单但是我没想出来 幸好第二题数据比较水...我垃圾暴力都水过了

技术分享图片

 

这道题倒着搞 正着搞其实是一样的 

因为要保证最后的珠子递增 所以就优先保证最后一个珠子放在空着的最后一个位置 其他的珠子就乱放就可以了

每次空着的位置减一下就可以了

代码

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N = 5 * 1e5 + 5;
const ll MOD = 998244353;
ll ans,fac[N],rfac[N];
int n,num[N],sum;

ll fast_pow(ll a,ll b) {
    
    ll ans = 1;
    for(;b;b >>= 1,a = a * a % MOD)
        if(b & 1) ans = ans * a % MOD;
    return ans;
}

ll reverse(ll a) {
    
    return fast_pow(a,MOD - 2);
}

ll C(int i, int j) {
    
    return fac[i] * rfac[i - j] % MOD * rfac[j] % MOD;
}

void Init( ) {
    
    scanf("%d",& n);
    for(int i = 1;i <= n;i ++) {
        scanf("%d",& num[i]);
        sum += num[i];
    }
    fac[0] = 1,rfac[0] = 1;
    for(int i = 1;i <= 500000;i ++) {
        fac[i] = fac[i - 1] * i % MOD;
        rfac[i] = reverse(fac[i]);
    }
}

void Solve( ) {
    
    ans = 1;
    for(int i = n;i >= 1;i --) {
        ans = (ans * C(sum - 1,num[i] - 1)) % MOD;
        sum -= num[i];
    }
    printf("%lld",ans);
}

int main( ) {
    
    freopen("qiang.in","r",stdin);
    freopen("qiang.out","w",stdout);
    Init( );
    Solve( );
}

技术分享图片

因为这个每一行的转移是一样的 所以和轮廓线dp一样的思路

然后使用矩阵快速幂加速转移 然后因为我一直都不是很会矩阵快速幂...

先高高冯dalao的代码把

代码

#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);    
    }
    
}

技术分享图片

技术分享图片

技术分享图片

这道题真的很神奇了

我感觉我至今还没有完全理解

先处理出一个数组表示从$a$到$b$需要多少次操作 如果某段区间内次数是单调递减的 说明这段区间的操作次数为最大的那个

处理出一个值表示将上一个位置的区间延展到现在的位置需要的代价 也是重新开几个次数的代价

因为我们要付出这个代价 就将当前区间的次数搞成4了 或者是当前的位置新开的代价

而我们每次选择最少钱的方案搞 所以如果小的在前面 它就相当于他那个位置补齐 否则是新加的 都能延展到这个位置

然后就每次选择一个最少的方案搞就可以了 (其实我也不是很理解 当以后更厉害了再来看)

代码

#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 5;
int n,T,ans,a[N],b[N],c[N],s[5];
bool vis[N];

void Solve( ) {
    
    scanf("%d",& T);
    while(T --) {
        scanf("%d",& n); ans = 0;
        for(int i = 1;i <= n;i ++) scanf("%d",& a[i]);
        for(int i = 1;i <= n;i ++) scanf("%d",& b[i]);
        for(int i = 1;i <= n;i ++) {
            if(b[i] == a[i]) c[i] = 0;
            else if(b[i] > a[i]) c[i] = b[i] - a[i];
            else c[i] = b[i] + 4 - a[i];
        }
        memset(s,0,sizeof(s));
        ans = c[1];
        for(int i = 2;i <= n;i ++) {
            s[((c[i] - c[i - 1]) % 4 + 4) % 4] ++;
            if(c[i] <= c[i - 1]) continue;
            int j;
            for(j = 1;s[j] == 0;j ++);
            s[j] --;
            ans += j;
        }
        printf("%d\n",ans);
    }
}

int main( ) {
    
    freopen("sequence.in","r",stdin);
    freopen("sequence.out","w",stdout);
    Solve( );
}

 

18.9.18 考试总结

标签:表示   lin   mic   http   void   open   怎么办   付出   ...   

原文地址:https://www.cnblogs.com/Rubenisveryhandsome/p/9670122.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!