校内集训20180918

$T1:$(Loj507

$N$张扑克牌依次添加,花色为$a_i$,点数为$b_i$,每添加一张牌$i$可以选择另一张花色相同的牌$j$并把$j,j+1,\ldots,i$的牌移走,产生这些牌点数之和的贡献,问最多

产生多少贡献。

$N\leq 2\times 10^6$,时限$600ms$。

 

题解:

$O(N^2)DP$不是重点,重点是如何优化$dp[i]=max(dp[i],dp[j-1]+sum[i]-sum[j-1]|a_j==a_i)$这个方程。

可以发现$dp[i]=sum[i]+max\{dp[j-1]-sum[j-1]|aj==ai\}$,那么我们考虑对每个颜色维护当前最大的$dp[j-1]-sum[j-1]$,即可$O(1)$转移。

傻逼题$100pts$没有挂。

 

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>

using namespace std;
#define MAXN 1000005
#define MAXM 500005
#define INF 1LL<<50
#define ll long long

ll dp[MAXN],c[MAXN],v[MAXN];
ll maxn[MAXN],sum[MAXN];
inline ll read(){
    ll x=0,f=1;
    char c=getchar();
    for(;!isdigit(c);c=getchar())
        if(c=='-')
            f=-1;
    for(;isdigit(c);c=getchar())
        x=x*10+c-'0';
    return x*f;
}

int main(){
    ll N=read(),K=read();
    for(ll i=1;i<=N;i++) c[i]=read();
    for(ll i=1;i<=K;i++) maxn[i]=-INF;
    for(ll i=1;i<=N;i++) v[i]=read(),sum[i]=sum[i-1]+v[i];
    for(ll i=1;i<=N;i++){
        dp[i]=max(dp[i-1],sum[i]+maxn[c[i]]);
        /*for(ll j=1;j<i;j++)
            if(c[j]==c[i]){
                dp[i]=max(dp[i],sum[i]+dp[j-1]-sum[j-1]);
            }*/
        maxn[c[i]]=max(maxn[c[i]],dp[i-1]-sum[i-1]);
    }
    printf("%lld\n",dp[N]);
    return 0;
}
/*

18 5
5 2 3 5 1 3 5 2 1 4 2 4 5 4 1 1 1 5
8 2 7 6 10 8 10 9 10 2 4 7 7 7 7 9 7 3
*/

 

$T2:$(Loj2279

给定$N$个年份和该年的降水量,再给定$Q$个问题,每个问题由$(Y,X)$表示,判断“$X$年是$Y$年以来降水量最多的”这句话是否正确。

注意$Y\sim X$之间的降水量不一定是给定的,如果不能判断是否正确则输出不确定。

$N\leq 50000$,空间限制$64MB$。

 

题解:

如果没有不确定这个选项那么就是一个$ST$表模板。

然而现在要写巨大的一个分类讨论。

理论上来说只需要在确定的基础上判断若$Y\sim X$中间有任意一点未知则不确定。

然而我好像写丑了。

码农题$0pts$喜闻乐见。

 

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>

using namespace std;
#define MAXN 50005
#define MAXM 500005
#define INF 0x7fffffff
#define ll long long

int year[MAXN],level[MAXN];
int N,f[MAXN][17],log2[MAXN];
inline int read(){
    int x=0,f=1;
    char c=getchar();
    for(;!isdigit(c);c=getchar())
        if(c=='-')
            f=-1;
    for(;isdigit(c);c=getchar())
        x=x*10+c-'0';
    return x*f;
}

void init(){
    log2[1]=0;
    for(int i=2;i<=MAXN;i++) log2[i]=log2[i>>1]+1;
    for(int i=1;i<=N;i++) f[i][0]=level[i];
    for(int j=1;j<17;j++)
        for(int i=1;i+(1<<j-1)<=N;i++)
            f[i][j]=max(f[i][j-1],f[i+(1<<j-1)][j-1]);
    return;    
}

int main(){
    //freopen("1 (1).in","r",stdin);
    //freopen("2.ans","w",stdout);
    N=read();
    for(int i=1;i<=N;i++) year[i]=read(),level[i]=read();
    init(); int M=read();
    for(int i=1;i<=M;i++){
        int Y=read(),X=read();
        if(Y>=X){
            cout<<"false"<<endl;
            continue;
        }
        int t1=lower_bound(year+1,year+1+N,Y)-year;
        int t2=lower_bound(year+1,year+1+N,X)-year;
        //cout<<t1<<":"<<t2<<endl;
        if(year[t1]!=Y && year[t2]!=X){
            cout<<"maybe"<<endl;
            continue;
        }
        else if(year[t1]!=Y && year[t2]==X){
            if(t1==t2){
                cout<<"maybe"<<endl;
                continue;
            }
            else{
                t2--;int k=log2[t2-t1+1];
                int maxn=max(f[t1][k],f[t2-(1<<k)+1][k]);
                if(maxn>=level[t2+1]) cout<<"false"<<endl;
                else cout<<"maybe"<<endl;
                continue;
            }
        }
        else if(year[t2]!=X && year[t1]==Y){
            if(t1+1==t2){
                cout<<"maybe"<<endl;
                continue;
            }
            else{
                t2--;t1++;int k=log2[t2-t1+1];
                int maxn=max(f[t1][k],f[t2-(1<<k)+1][k]);
                if(maxn>=level[t1-1]) cout<<"false"<<endl;
                else cout<<"maybe"<<endl;
                continue;
            }
        }
        else{
            if(t1+1==t2){
                if(level[t2]<=level[t1]){
                    if(t2-t1+1==X-Y+1) cout<<"true"<<endl;
                    else cout<<"maybe"<<endl;
                }
                else cout<<"false"<<endl;
                continue;
            }
            else{
                t2--;t1++;int k=log2[t2-t1+1];
                int maxn=max(f[t1][k],f[t2-(1<<k)+1][k]);
                if(maxn>=level[t1-1] || maxn>=level[t2+1] || level[t2+1]>level[t1-1]) cout<<"false"<<endl;
                else if(t2-t1+3==X-Y+1) cout<<"true"<<endl;
                else cout<<"maybe"<<endl;
                continue;
            }
        }
    }
    return 0;
}

 

$T3:$(Loj2332

给你$i$个数,若$A_i\geq A_{i-1}$则$T_i=-(A_i-A_{i-1})\times S$,否则$T_i=-(A_i-A_{i-1})\times T$,有$M$组更新$(L,R)$将$[L,R]$区间内的$A_i\rightarrow A_{i+v}$。

每次更新后输出$ans=\sum T_i$的值。

$N\leq 2\times 10^5$,时限$200ms$。

 

题解:

考场上一直在想怎么把线段树优化过时限。于是$0pts$。

后来考完一想,$T$每次更新只需要更俩数,$ans$只需要把这更新的俩数值加上再减去原值就行了。

在线求助智力康复学校。

 

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>

using namespace std;
#define MAXN 200005
#define MAXM 500005
#define INF 0x7fffffff
#define ll long long

ll N,Q,S,T,A[MAXN],B[MAXN];
inline ll read(){
    ll x=0,f=1;
    char c=getchar();
    for(;!isdigit(c);c=getchar())
        if(c=='-')
            f=-1;
    for(;isdigit(c);c=getchar())
        x=x*10+c-'0';
    return x*f;
}

ll calc(ll x){return x>0?-x*S:-x*T;}

int main(){
    N=read(),Q=read(),S=read(),T=read();
    ll ans=0; 
    for(ll i=0;i<=N;i++){
        A[i]=read();if(!i) continue;
        B[i]=A[i]-A[i-1];ans+=calc(B[i]);
    }
    //cout<<sum[N+1]<<endl;
    while(Q--){
        ll l=read(),r=read(),v=read();
        ans-=calc(B[l]);B[l]+=v;ans+=calc(B[l]);
        if(r!=N) ans-=calc(B[r+1]),B[r+1]-=v,ans+=calc(B[r+1]);
        printf("%lld\n",ans);
    }
    return 0;
}

 

总结:

三道“思维”题$100pts$收场喜闻乐见。

正如$Lv$神所言:“这样去考$noip$还不如回家洗洗睡”。

的确像这种题目都不能保证$100%AC$还拿什么$noip$高分,不如去搞文化课了。

模拟考试的时候手懒,$noip$的时候可能就一直懒下去了吧。

后面几场模拟考试要认真打了,不然在这耗$3h$有什么意义呢。

共勉。

 

posted @ 2018-09-19 01:01  Fugtemypt  阅读(171)  评论(0编辑  收藏  举报