NOIP模拟题 [模拟][DP][线段树]

时间:2022-12-17 00:20:34

抽象题目所求性质。
熟练模板。

T1:
题意:
把一序列重复,求一区间内某字符出现次数。
分析:
显然把超出该区间长度的直接乘法算就行了,注意一下并区间,区间从1开始导致len取不到的问题处理。思路很简单,但可能会被包装在比较难的题里面。

解锁新错误:读入优化没开longlong
不知道什么时候才能把这些傻逼错集齐。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<string>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<vector>
#include<vector>
using namespace std;
#define ll long long
#define inf 1e8
#define clr(x) memset(x,0,sizeof(x))
#define maxen(x) memset(x,127,sizeof(x))
#define maxer(x) memset(x,31,sizeof(x))
#define minus(x) memset(x,-1,sizeof(x))
#define minn(a,b,c) min(a,min(b,c))
#define maxx(a,b,c) max(a,max(b,c))
#ifdef WIN32
#define lld "%I64d"
#else
#define lld "%lld"
#endif
#define PROC "a"
const int Maxn=105;
ll len,lef,rig,ans,tot;
char a[Maxn];
long long read()
{
    long long x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(long long)(ch-'0');ch=getchar();}
    return x*f;
}
void init()
{
    cin.getline(a+1,Maxn);
    len=strlen(a+1);
    for(int i=1;i<=len;i++)
        if(a[i]=='B')
            tot++;
    lef=read();rig=read();
    a[0]=a[len];
}
void work()
{
    if(rig-lef+1LL>=len){
        ans+=(rig-lef+1LL)/len*tot;
        rig-=(rig-lef+1LL)/len*len;
    }
    if(rig>=lef){
    for(int i=lef;i<=rig;i++)
        if(a[i%len]=='B')ans+=1LL;
    }
    printf("%I64d",ans);
}
int main()
{
    freopen(PROC".in","r",stdin);
    freopen(PROC".out","w",stdout);
    init();
    work();
    return 0;
}

T2:
题意:
从n个蛋糕里选m个吃,且先吃i再吃j可能会使美味值增加,球最后能获得的最大美味值。
分析:
本来当成背包加一维来做,后来发现显然会重,于是刷刷刷敲了个状压,可惜还是没能挽救我的T3和静查。以及,估计时间复杂度的时候,这种状压的数值一定要精确,我差点以为要T。
状压表示选了哪些,然后枚举第二维(最后选的),再枚举前一个(要求在已选的里)来修改当前状态即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<string>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<vector>
#include<vector>
using namespace std;
#define ll long long
#define inf 1e8
#define clr(x) memset(x,0,sizeof(x))
#define maxen(x) memset(x,127,sizeof(x))
#define maxer(x) memset(x,31,sizeof(x))
#define minus(x) memset(x,-1,sizeof(x))
#define minn(a,b,c) min(a,min(b,c))
#define maxx(a,b,c) max(a,max(b,c))
#ifdef WIN32
#define lld "%I64d"
#else
#define lld "%lld"
#endif
#define PROC "b"
const int Maxn=20,Maxn2=3e5+5;
ll f[Maxn2][Maxn],c[Maxn][Maxn],ans;
ll n,m,k,x,y,a[Maxn];
ll read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}
void init()
{
    n=read();m=read();
    k=read();
    for(int i=1;i<=n;i++)
        a[i]=read();
    for(int i=1;i<=k;i++){
        x=read();y=read();
        c[x][y]=read();
    }
}
void work()
{
    for(int i=1;i<(1<<n);i++){
    int flg=0;
    ll ans2=0;
        for(int j=1;j<=n;j++)
            if(i&(1<<(j-1))){
            for(int k=1;k<=n;k++)
                if(i&(1<<(k-1))&&k!=j)
                    f[i][j]=max(f[i][j],f[i^(1<<(j-1))][k]+a[j]+c[k][j]);
            if(!f[i][j])f[i][j]=a[j];
            flg++;ans2=max(ans2,f[i][j]);
            }
    if(flg==m)ans=max(ans,ans2);
    }
    printf("%I64d",ans);
}
int main()
{
    freopen(PROC".in","r",stdin);
    freopen(PROC".out","w",stdout);
    init();
    work();
    return 0;
}

T3:
题意:
每次把一棵树及其子树上点加上一值(每往下走一层加1),在线询问某一点及其子树权值和。
分析:
记得一位大神说,如果你写的程序慢,说明你没发掘问题特有的性质。
这道题并不是一道简单的数据结构,里面涉及到本问题一个特有的特性:子节点比父节点多加1,这个可以很容易让我们想起来深度,然后就会发现,加上的权值里,是k-dep[fa]+dep[son],然后本来采用线段树(因为一看就要带log)的难点:pushdown就可以迎刃而解:分别存k-dep[fa]的和以及dep[son]出现的次数即可;(这样就把每个点不同的值抽象成了同一种表示!)
然后线段树上维护这两个值即可。

吐槽一句:我线段树太丑了,标记还没累加直接T成暴力,幸好NOIP前发现了不然要完。

再吐槽一句:听说我压码能力很强,把别人200+行的代码带模板直接压成了140?(手动萌币

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<string>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<vector>
#include<vector>
#define ll long long
#define inf 1e8
#define clr(x) memset(x,0,sizeof(x))
#define maxen(x) memset(x,127,sizeof(x))
#define maxer(x) memset(x,31,sizeof(x))
#define minus(x) memset(x,-1,sizeof(x))
#define minn(a,b,c) min(a,min(b,c))
#define maxx(a,b,c) max(a,max(b,c))
#ifdef WIN32
#define lld "%I64d"
#else
#define lld "%lld"
#endif
#define PROC "c"
const int Maxn=5e4+5;
int fr[Maxn],tov[Maxn],w[Maxn],wrev[Maxn],tail[Maxn];
int dep[Maxn];
int n,p,cnt;
struct node
{
    int lef,rig,bj2;
    ll bj,tot,sum,depsum,a;
}a[Maxn*4];
int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}
void addedge(int cur)
{
    int nowy=read();
    tov[cur]=fr[nowy];
    fr[nowy]=cur;
}
void dfs(int cur,int fa)
{
    dep[cur]=dep[fa]+1;
    w[cur]=++cnt;wrev[cnt]=cur;
    for(int i=fr[cur];i;i=tov[i])
        dfs(i,cur);
    tail[cur]=cnt;
}
void build(int u,int lef,int rig)
{
    a[u].lef=lef;a[u].rig=rig;
    if(lef==rig){
        a[u].depsum=dep[wrev[lef]];
        return;
    }
    int mid=(a[u].lef+a[u].rig)>>1;
    build(2*u,lef,mid);
    build(2*u+1,mid+1,rig);
    a[u].depsum=a[2*u].depsum+a[2*u+1].depsum;
}
void init()
{
    n=read();p=read();
    for(int i=2;i<=n;i++)
        addedge(i);
    dfs(1,0);
    build(1,1,n);
}
void pushdown(int u)
{   
    a[u].tot+=a[u].bj2;
    a[u].a+=a[u].bj*(a[u].rig-a[u].lef+1);
    a[u].sum+=a[u].bj2*a[u].depsum+a[u].bj*(a[u].rig-a[u].lef+1);
    if(a[u].lef!=a[u].rig){
    a[2*u].bj+=a[u].bj;
    a[2*u+1].bj+=a[u].bj;
    a[2*u].bj2+=a[u].bj2;
    a[2*u+1].bj2+=a[u].bj2;
    }
    a[u].bj=a[u].bj2=0;
}
void update(int u,int lef,int rig,int wor)
{
    if(a[u].lef==lef&&a[u].rig==rig){
        a[u].bj+=wor;
        a[u].bj2++;
        pushdown(u);
        return;
    }
    if(a[u].bj2)pushdown(u);
    int mid=(a[u].lef+a[u].rig)>>1;
    if(rig<=mid)update(2*u,lef,rig,wor);
    else if(lef>mid)update(2*u+1,lef,rig,wor);
    else {
    update(2*u,lef,mid,wor);
    update(2*u+1,mid+1,rig,wor);
    }
    if(a[2*u].bj2)pushdown(2*u);
    if(a[2*u+1].bj2)pushdown(2*u+1);
    a[u].sum=a[2*u].sum+a[2*u+1].sum;
}
ll query(int u,int lef,int rig)
{
    if(a[u].bj2)pushdown(u);
    if(a[u].lef==lef&&a[u].rig==rig)
        return a[u].sum;
    int mid=(a[u].lef+a[u].rig)>>1;
    if(rig<=mid)return query(2*u,lef,rig);
    else if(lef>mid)return query(2*u+1,lef,rig);
    else return query(2*u,lef,mid)+query(2*u+1,mid+1,rig);
}
void work()
{
    for(int i=1;i<=p;i++){
        char b[5];
        scanf("%s",b);
        if(b[0]=='Q'){
        int u=read();
        printf("%I64d\n",query(1,w[u],tail[u]));
        }
        else {
        int u=read();
        update(1,w[u],tail[u],read()-dep[u]);
        }
    }

}
int main()
{
    freopen(PROC".in","r",stdin);
    freopen(PROC".out","w",stdout);
    init();
    work();
    return 0;
}