ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

NOIP 模拟 七十八

2021-10-17 11:33:43  阅读:146  来源: 互联网

标签:cnt NOIP int res 七十八 dpi inline 模拟 mod


100+30+30+100

T1 F

x 只可能有 n 种情况,枚举每个 x,暴力扫一个数组找到所需的另一个值,然后开个桶判断是否合法即可。

#include<bits/stdc++.h>
using namespace std;
int n,m,a[4001],b[4001],tong[4001],tot,san[4001],id[4001];
set<int>st;
inline bool check(int x)
{   if(st.find(x)!=st.end())return 0;
    for(int i=2;i<=n;++i)
    {   int y=a[i]^x;
        int id=lower_bound(san+1,san+1+tot,y)-san;
        if(san[id]!=y)return 0;
        if(!tong[id])return 0;
        --tong[id];
    }
    return 1;
}
signed main()
{   freopen("f.in","r",stdin);  
    freopen("f.out","w",stdout);
    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]),san[++tot]=b[i];
    sort(san+1,san+1+tot);tot=unique(san+1,san+1+tot)-san-1;san[tot+1]=1e9+1;
    for(int i=1;i<=n;++i)id[i]=lower_bound(san+1,san+1+tot,b[i])-san;
    for(int i=1;i<=n;++i)
    {   for(int j=1;j<=n;++j)tong[j]=0;
        for(int j=1;j<=n;++j)tong[id[j]]++;
        int x=a[1]^b[i];tong[id[i]]--;
        if(check(x))st.insert(x);
    }
    printf("%d\n",(int)st.size());
    for(auto i:st)printf("%d\n",i);
}

T2 S

神仙dp,我不会。瞎扫混了30。

考虑到交换后每种颜色内部的相对顺序不会改变,而交换次数实质就是逆序对数,于是可以 dp 构造出逆序对最小的序列。

#include<bits/stdc++.h>
using namespace std;
char a[501];
int n,ans,seq[501],tong[501],cnt[501][3],f[401][401][3],g[401][401][3];
vector<int>p[3];
inline bool check()
{   for(int i=2;i<=n;++i)if(seq[i]==seq[i-1])return 0;
    return 1;
}
signed main()
{   freopen("s.in","r",stdin);
    freopen("s.out","w",stdout);
    scanf("%d",&n);scanf("%s",a+1);
    for(int i=0;i<=2;++i)p[i].push_back(0);
    for(int i=1;i<=n;++i)
    {   if(a[i]=='R')seq[i]=0;
        if(a[i]=='G')seq[i]=1;
        if(a[i]=='Y')seq[i]=2;
        for(int opt=0;opt<=2;++opt)cnt[i][opt]=cnt[i-1][opt];
        cnt[i][seq[i]]++;p[seq[i]].push_back(i);
    }
    if(cnt[n][0]>(n+1)/2 or cnt[n][1]>(n+1)/2 or cnt[n][2]>(n+1)/2){puts("-1");return 0;}
    memset(f,0x3f3f3f3f,sizeof(f));if(cnt[n][0])f[1][0][0]=0;if(cnt[n][1])f[0][1][1]=0;if(cnt[n][2])f[0][0][2]=0;
    for(int i=1;i<n;++i)
    {   memset(g,0x3f3f3f3f,sizeof(g));
        int numa=min(cnt[n][0],i);
        for(int a=0;a<=numa;++a)
        {   int numb=min(i-a,cnt[n][1]);
            for(int b=0;b<=numb;++b)
            {   int c=i-a-b;
                for(int opt=0;opt<=2;++opt)
                {   if(f[a][b][opt]==0x3f3f3f3f)continue;
                    if(opt!=0 and a+1<=cnt[n][0])g[a+1][b][0]=min(g[a+1][b][0],f[a][b][opt]+max(0,b-cnt[p[0][a+1]][1])+max(0,c-cnt[p[0][a+1]][2]));
                    if(opt!=1 and b+1<=cnt[n][1])g[a][b+1][1]=min(g[a][b+1][1],f[a][b][opt]+max(0,a-cnt[p[1][b+1]][0])+max(0,c-cnt[p[1][b+1]][2]));
                    if(opt!=2 and c+1<=cnt[n][2])g[a][b][2]=min(g[a][b][2],f[a][b][opt]+max(0,a-cnt[p[2][c+1]][0])+max(0,b-cnt[p[2][c+1]][1]));
                }
            }
        }    
        numa=min(i+1,cnt[n][0]);
        for(int a=0;a<=numa;++a)
        {   int numb=min(i+1-a,cnt[n][1]);
            for(int b=0;b<=numb;++b)for(int opt=0;opt<=2;++opt)f[a][b][opt]=g[a][b][opt];
        }
    }
    printf("%d\n",min(f[cnt[n][0]][cnt[n][1]][0],min(f[cnt[n][0]][cnt[n][1]][1],f[cnt[n][0]][cnt[n][1]][2])));
}

T3

神仙dp,我不会,暴搜30。

发现肯定有一个人拿出了 0 个,因为全局减一会抵消掉,然后dp。

我们先做一些初步分析,设每个点往后给了 ci,若 ∀ci > 0,那么我们可以全部 −1。
于是我们考虑枚举一个 0,这样这个点是没有往后放的,就可以破环为链。
为了避免重复计数,我们枚举第一个0,强制前面没有0。此时,我们计算所有情况的贡献
和。此时,我们暴力设 dpi,j 表示到 i,给后面 j 个的贡献,那么有 dpi,j = (ai + k −j)dpi−1,k。
我们注意到只需要维护 ∑dpi,j , ∑dpi,j ×j 就可以完成转移。此时复杂度 O(n2)。注意到
转移可以写成一个 2 ×2 的矩阵乘法,我们维护一个前后缀就可以了。复杂度 O(n)。

#include<bits/stdc++.h>
#define N 1000005
#define int long long
using namespace std;
const int mod=1000000007,inv2=500000004,inv6=166666668;
int n,a[N],f[N][2],minn=1e18,ans;
inline int calc1(int x){return x%mod*((x+1)%mod)%mod*inv2%mod;}
inline int calc2(int x){return x%mod*((x+1)%mod)%mod*((2*x+1)%mod)%mod*inv6%mod;}
inline int work(int sta,int lim)
{   memset(f,0,sizeof(f));f[1][sta]=1;
    for(int i=1;i<=n;++i)f[i+1][0]=(f[i+1][0]+f[i][0]*calc1(a[i]-lim)%mod+f[i][1]*(a[i]+1-lim)%mod+mod)%mod,
    f[i+1][1]=(f[i+1][1]+f[i][0]*((a[i]*calc1(a[i])%mod-calc2(a[i])+mod)%mod)%mod+f[i][1]*calc1(a[i])%mod+mod)%mod;
    return f[n+1][sta];
}
signed main()
{   freopen("y.in","r",stdin);
    freopen("y.out","w",stdout);
    scanf("%lld",&n);for(int i=1;i<=n;++i)scanf("%lld",&a[i]),minn=min(a[i],minn);
    ans=(work(0,0)+work(1,0))%mod;if(minn)ans=(ans-work(1,1)-work(0,1)+mod*2)%mod;printf("%lld\n",ans);
}

T4 O

我猜数据不会很强。。。

大数据不可能全部单调递减。。。

然后数据真是随出来的。。

甚至精心构造了单调递增的序列。。。

然后暴力修改就跑过了。

题目即为:给出 ai,每次问 (t, l, r) 表示 ∑r
i=l maxi−t≤j≤iaj
考虑向前面第一个大于它的连边,那么会变成一颗树,那么就是每个点不断往上跳,然后
求和。
我们考虑枚举每条边,求出它被跳过的次数,设它的子树是 [i, ri),权值为 c 那么它会对
x ∈[i, ri), y ≥p −t 的点加上 c,记 x ≥a, y ≥x −b 的修改为 (a, b, c)。
差分成两个直角三角形,从下往上扫描线。
考虑询问前缀 p,那么贡献就是 c(min(p, b + t) −min(p, a)) 容易注意到两维已经独立开
了,分别前缀加前缀求和就可以了(前面变成 t + min(p −t, b))

#include<bits/stdc++.h>
#define int long long
#define N 200050
using namespace std;
int maxn[N<<2],sum[N<<2],n,q,a[N],sta[N],top,ans[N];
vector<pair<int,int> >ve[N];
struct jj
{int times,l,r,id;}Q[N];
inline void pushup(int x)
{   sum[x]=sum[x<<1]+sum[x<<1|1];
    maxn[x]=max(maxn[x<<1],maxn[x<<1|1]);
}
inline void build(int x,int l,int r)
{   if(l==r){sum[x]=maxn[x]=a[l];return;}
    int mid=(l+r)>>1;
    build(x<<1,l,mid);build(x<<1|1,mid+1,r);
    pushup(x);
}
inline int qmax(int x,int l,int r,int L,int R)
{   if(l>=L and r<=R)return maxn[x];
    int mid=(l+r)>>1,res=0;
    if(mid<R)res=max(res,qmax(x<<1|1,mid+1,r,L,R));
    if(mid>=L)res=max(res,qmax(x<<1,l,mid,L,R));
    return res;
}
inline void ins(int x,int l,int r,int pos,int val)
{   sum[x]+=val;if(l==r)return;
    int mid=(l+r)>>1;
    if(mid<pos)ins(x<<1|1,mid+1,r,pos,val);
    else ins(x<<1,l,mid,pos,val);
}
inline int qsum(int x,int l,int r,int L,int R)
{   if(l>=L and r<=R)return sum[x];
    int mid=(l+r)>>1,res=0;
    if(mid<R)res+=qsum(x<<1|1,mid+1,r,L,R);
    if(mid>=L)res+=qsum(x<<1,l,mid,L,R);
    return res;
}
inline void work()
{for(int i=1;i<=q;++i)printf("%lld\n",qmax(1,1,n,max(1ll,Q[i].l-Q[i].times),Q[i].l));}
inline bool cmp(jj i,jj j){return i.times<j.times;}
signed main()
{   freopen("o.in","r",stdin);
    freopen("o.out","w",stdout);
    scanf("%lld%lld",&n,&q);   
    for(int i=1;i<=n;++i)scanf("%lld",&a[i]);
    build(1,1,n);bool bo=1;
    for(int i=1;i<=q;++i)
    {   scanf("%lld%lld%lld",&Q[i].times,&Q[i].l,&Q[i].r);Q[i].id=i;
        if(Q[i].l!=Q[i].r)bo=0;
    }
    if(bo){work();return 0;}
    for(int i=1;i<=n;++i)
    {   while(top and a[sta[top]]<=a[i])--top;
        sta[++top]=i;
        for(int j=top-1;j;--j)ve[i-sta[j]].push_back(make_pair(i,a[sta[j]]-a[sta[j+1]]));

    }
    sort(Q+1,Q+1+q,cmp);int zhi=0;
    for(int i=1;i<=q;++i)
    {   while(zhi+1<=Q[i].times)
        {   ++zhi;
            for(auto j:ve[zhi])ins(1,1,n,j.first,j.second);
        }
        ans[Q[i].id]=qsum(1,1,n,Q[i].l,Q[i].r);
    }
    for(int i=1;i<=q;++i)printf("%lld\n",ans[i]);
}

标签:cnt,NOIP,int,res,七十八,dpi,inline,模拟,mod
来源: https://www.cnblogs.com/zhaoxubing/p/15416469.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有