无题十二

今天的题都有思路,但都搞不出来;

题解:

第一题:我看到数据范围想到了矩阵快速幂,实际上是不需要的,每次暴力乘组合数就好了,因为原来dp[i]对应前面多项,而这回dp[i]对应的dp[i-n]是唯一确定的;

确定了前n行,后面每一行放多少就唯一确定,只需要一直乘方案数;

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int M = 105;
const int mod=1e9 + 7;
int c[M][M], dp[M][M*M], f[M][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 int moc(int a){return a >= mod ? a - mod : a;}
int main(){
    freopen("chess.in","r",stdin);
    freopen("chess.out","w",stdout);
    int n, C;
    ll m;
    scanf("%d%lld%d", &n, &m, &C);
    for(int i = 0; i <= n; i++)
        for(int j = 0; j <= i; j++)
            if(j == 0 || i == j) c[i][j] = 1;
            else c[i][j] = moc(c[i-1][j] + c[i-1][j-1]);
    for(int i = 1; i <= n; i++)
        for(int j = 0; j <= n; j++)
            f[i][j] = ksm(c[n][j], (m-i)/n + 1);
    dp[0][0] = 1;
    for(int i = 1; i <= n; i++){
        for(int j=0; j <= i*n && j <= C; j++){
            int L = min(n, j);
            for(int t = 0; t <= L; t++){
                dp[i][j] = moc(dp[i][j] + (ll)dp[i-1][j-t]*f[i][t]%mod);
            }
        }
    }
    printf("%d\n", dp[n][C]);
}
View Code

第二题:可以先用一个栈处理出每个K对应的右边第一个小于他的未知,中间的元素都>=a[k],所以只需要在中间找一个最大值且最靠左的位置,就可以最大K的最大贡献了,对应找最大值我用了一课线段数,时间空间都不行;

考虑在弹栈的时候一并解决,pos[t]表示从栈中t这个位置到栈前下一个位置这段区间中的最大值的位置,每次弹栈时就自上往下取最大的MAX,如果栈空了,就把之前的贡献都去掉;

我觉得我还是说不清楚,还是看代码吧,特别鸣谢:zjj

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

const int M = 1e7 + 5;
int n, a[M], q[M];
int read(){
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*=f;    
}
int pos[M];
int main(){
    freopen("array.in","r",stdin);
    freopen("array.out","w",stdout);
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) a[i] = read();
    a[n + 1] = 0;
    int ans = 0;
    int h = 1, t = 1; q[1] = 1;
    pos[1]=1;
    int mx = 0;
    for(int i = 2; i <= n + 1; i++){
        int res= i - 1,mx = a[i - 1];
        while(h <= t && a[i] < a[q[t]]){
            ans = max(ans, res - q[t] + 1);
            if(a[pos[t]] == mx) res = max(q[t], res);
            else if(a[pos[t]] > mx) res = pos[t], mx = a[pos[t]];    
            t--;
        }    
        if(h > t)
        {
        q[++t] = i;
        pos[t] = i;
        continue;
        } 
       if(a[i] >= mx)
        {
            mx = a[i];
            res = i;
        }
        q[++t] = i;
        pos[t] = res;
    }
    printf("%d\n", ans);
}

第三题:本来是莫队+线段树统计最长连续子段和,但我真的不知道那里写挂了;

正解:回滚莫队,只带增添不带删减的莫队,每次记录版本的答案,右边一直延展,左边一直回滚

#include<bits/stdc++.h>
using namespace std;
const int M = 1e5 + 5;
int n, m, a[M], ans[M];
struct Query{int l, r, id;}q[M], qs[M];
bool cmp1(Query A, Query B){return A.l < B.l;}
bool cmp2(Query A, Query B){return A.r < B.r;}
int read(){
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*=f;    
}
int L[M], R[M], vis[M], TTT, skt[M], tp, has[M], now_ans;
void update(int t){
    if(vis[t] != TTT) vis[t] = TTT, L[t] = R[t] = t, has[t] = 0;
}

void add(int t, bool f){
    update(t), update(t+1), update(t-1);
    int lf=L[t],rg=R[t];
    if(t!=1 && has[t-1]) lf=L[t-1];
    if(t!=n && has[t+1]) rg=R[t+1];
    now_ans = max(rg - lf + 1, now_ans);
    R[lf] = rg, L[rg] = lf;
    has[t] = 1;
    if(f) skt[++tp] = t;
}
void restore(){
    while(tp){
        int t=skt[tp];tp--;
        has[t] = 0;
        if(t!=1 && has[t-1]) R[L[t-1]]=t-1;
        if(t!=n && has[t+1]) L[R[t+1]]=t+1;
    }
}

int main(){
    freopen("cc.in","r",stdin);
    freopen("ants.out","w",stdout);
    n = read(), m = read();
    for(int i = 1; i <= n; i++) a[i] = read();
    for(int i = 1; i <= m; i++) q[i].l = read(), q[i].r = read(), q[i].id = i;
    sort(q + 1, q + 1 + m, cmp1);
    int siz = sqrt(n + 0.5), now = 1;
    for(int i = 1, j = 1; i <= n && now <= m; i++){
        int up = min(i * siz, n), tot = 0;
        while(now <= m && q[now].l <= up)qs[++tot] = q[now++];
        if(!tot)continue; TTT++; 
        sort(qs + 1, qs + 1 + tot, cmp2);
        int now_r = up; now_ans = 1;
        for(int j = 1; j <= tot; j++){
            while(now_r < qs[j].r){
                int t = a[++now_r];
                add(t, 0);
            }
            int tmp = now_ans;
            for(int k = min(up, qs[j].r); k >= qs[j].l; k--) add(a[k], 1);
            ans[qs[j].id] = now_ans;
            restore();    
            now_ans = tmp;
        }
        
    }
    
    
    for(int i = 1; i <= m; i++) printf("%d\n", ans[i]);
}

猜你喜欢

转载自www.cnblogs.com/EdSheeran/p/9792368.html