CSP-S模拟5 F S Y O

T1:暴力枚举(找对枚举角度);T2:计数类DP;T3:矩阵优化DP;T4:数据结构:主席树/倍增拿【暴力】90分

T1:题目大意:给出a序列,b序列,长度是n,求a中每个数对应b中每个数的值都一样的值个数。(n<=2000)

不可以按照每一位相互独立统计互补情况,因为每一位独立,但是不能把一个数的每一位拆开,这个位和x1配,那位和x2配,如果考虑这种情况,
就需要每次分割都考虑配对,会很麻烦。
所以正解就考虑可能的x然后验证就行。发现最多n个,直接枚举然后暴力验证是否每个都可以配对,实现可以使set,当然一个map直接计数更方便。所以数据范围和灵活考虑答案的枚举角度和方式很重要

点击查看代码








#include<bits/stdc++.h>
using namespace std;
#define _f(i,a,b) for(register int i=a;i<=b;++i)
#define f_(i,a,b) for(register int i=a;i>=b;--i)
#define chu printf
#define ll long long
#define ull unsigned long long
inline ll re()
{
    ll x=0,h=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')h=-1;
        ch=getchar();
    }
    while(ch<='9'&&ch>='0')
    {
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*h;
}
const int N=2e5+10;
int n;
int a[2100],b[2100];
int ans[2100],cnt;
map<int,int>mp,tmp;
int xi[2100],tot;
inline int check(int val)
{
    tmp=mp;
    _f(i,1,n)
    {
        int goal=a[i]^val;
        if(tmp[goal]==0)return 0;
        tmp[goal]--;
    }
    return 1;
}
int main()
{
 freopen("f.in","r",stdin);
 freopen("f.out","w",stdout);
    n=re();
    _f(i,1,n)a[i]=re();
    _f(i,1,n)b[i]=re(),mp[b[i]]++;
    _f(i,1,n)
    xi[++tot]=a[1]^b[i];
    sort(xi+1,xi+1+tot);
    tot=unique(xi+1,xi+1+tot)-xi-1;
    _f(i,1,tot)
    if(check(xi[i]))ans[++cnt]=xi[i];
    chu("%d\n",cnt);
    _f(i,1,cnt)
    chu("%d\n",ans[i]);
    return 0;   
}
/*
枚举最大值最高位是多少,直接2^bit枚举异或和是多少:
O(2^bit*log(n)*n)
剪枝:
bita[x][0/1]=y:a里x位是0/1的个数,如果和b不互补一定不合法

3
1 2 3 
6 4 7 

2
0 1
0 2
*/

T2:n个球,排成一个序列,有“RGY”3种颜色,求最少交换次数,使得任意同色球

理解几个要点
(1)所有颜色球的相对位置关系不变一定是最优方案
(2)把原序列标号,则最终形态的答案数就是逆序对数。
设dp[i][j][k][0/1/2]:表示当前放i个R,j个G,k个Y,最后一个球是R/G/Y的最少逆序对数。
转移时,只需要考虑当前放的位置会相对前面产生多少逆序对,这个可以预处理,而且只来自于颜色不同的球。

点击查看代码



#include<bits/stdc++.h>
using namespace std;
#define _f(i,a,b) for(register int i=a;i<=b;++i)
#define f_(i,a,b) for(register int i=a;i>=b;--i)
#define chu printf
#define ll long long
#define ull unsigned long long
inline ll re()
{
    ll x=0,h=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')h=-1;
        ch=getchar();
    }
    while(ch<='9'&&ch>='0')
    {
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*h;
}
const int N=2e5+10;
int dp[210][210][210][3],n,pos[3];
pair<int,int>pre[3][210];
char bal[410];
int main()
{
  freopen("s.in","r",stdin);
  freopen("s.out","w",stdout);
    n=re();
    scanf("%s",bal+1);
    _f(i,1,n)
    {
        if(bal[i]=='R')pos[0]++,
        pre[0][pos[0]].first=pos[1],pre[0][pos[0]].second=pos[2];
        else  if(bal[i]=='G')pos[1]++,
        pre[1][pos[1]].first=pos[0],pre[1][pos[1]].second=pos[2];
        else if(bal[i]=='Y')pos[2]++,
        pre[2][pos[2]].first=pos[0],pre[2][pos[2]].second=pos[1];
    }
    int bj=(n+1)/2;
    if(pos[0]>bj||pos[1]>bj||pos[2]>bj)
    {
        chu("-1");return 0;
    }
    _f(a,0,pos[0])
    _f(b,0,pos[1])
    _f(c,0,pos[2])
    dp[a][b][c][0]=dp[a][b][c][1]=dp[a][b][c][2]=1e9;
    if(pos[0])
    {
        dp[1][0][0][0]=0;
    }
    if(pos[1])
    {
        dp[0][1][0][1]=0;
    }
    if(pos[2])
    {
        dp[0][0][1][2]=0;
    }
    _f(a,0,pos[0])
    _f(b,0,pos[1])
    _f(c,0,pos[2])
    {
        if(a)
        dp[a][b][c][0]=min(dp[a][b][c][0],min(dp[a-1][b][c][1],dp[a-1][b][c][2])+max(0,b-pre[0][a].first)+max(0,c-pre[0][a].second));
        if(b)
        dp[a][b][c][1]=min(dp[a][b][c][1],min(dp[a][b-1][c][0],dp[a][b-1][c][2])+max(0,a-pre[1][b].first)+max(0,c-pre[1][b].second));
        if(c)
        dp[a][b][c][2]=min(dp[a][b][c][2],min(dp[a][b][c-1][0],dp[a][b][c-1][1])+max(0,a-pre[2][c].first)+max(0,b-pre[2][c].second));
    }
    chu("%d",min(dp[pos[0]][pos[1]][pos[2]][0],min(dp[pos[0]][pos[1]][pos[2]][1],dp[pos[0]][pos[1]][pos[2]][2])));
    return 0;
}
/*
5
RRGYY
*/

T3:矩阵乘法优化DP

点击查看代码










#include<bits/stdc++.h>
using namespace std;
#define _f(i,a,b) for(register int i=a;i<=b;++i)
#define f_(i,a,b) for(register int i=a;i>=b;--i)
#define chu printf
#define ll long long
#define ull unsigned long long
inline ll re()
{
    ll x=0,h=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')h=-1;
        ch=getchar();
    }
    while(ch<='9'&&ch>='0')
    {
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*h;
}
const ll mod=1e9+7,inv2=500000004,inv6=166666668;
// inline ll S2(ll a)
// {
//     return a*(a+1)%mod*(2*a+1)%mod*inv6;
// }
int n;
ll a[1000000+100];
struct Node
{
    ll a1,a2,b1,b2;
    //Node(){a1=a2=b1=b2=0;}
    Node operator*(const Node&U)const
    {
        Node res;
        res.a1=(a1*U.a1%mod+a2*U.b1%mod)%mod;
        res.a2=(a1*U.a2%mod+a2*U.b2%mod)%mod;
        res.b1=(b1*U.a1%mod+b2*U.b1%mod)%mod;
        res.b2=(b1*U.a2%mod+b2*U.b2%mod)%mod;
        return res;
    }
}fro[1000000+10],bac[1000000+10],ans;
int main()
{
 freopen("y.in","r",stdin);
 freopen("y.out","w",stdout);
    n=re();
    fro[0]=(Node){1,0,0,1};
    bac[n+1]=(Node){1,0,0,1};
    _f(i,1,n)a[i]=re();
    _f(i,1,n)
    fro[i]=(Node){inv2*a[i]%mod*(a[i]+1)%mod,a[i]*(a[i]+1)%mod*(a[i]-1)%mod*inv6%mod,a[i]+1,inv2*a[i]%mod*(a[i]+1)%mod};
    _f(i,1,n)
    bac[i]=(Node){inv2*a[i]%mod*(a[i]-1)%mod,a[i]*(a[i]+1)%mod*(a[i]-1)%mod*inv6%mod,a[i],inv2*a[i]%mod*(a[i]+1)%mod};
    _f(i,1,n)
    fro[i]=fro[i-1]*fro[i];
    f_(i,n,1)
    bac[i]=bac[i]*bac[i+1];
    ll sum=0;
    _f(i,1,n)
    {
        ans=bac[i+1]*fro[i-1];
        sum=(sum+ans.a1*a[i]%mod+ans.a2)%mod;
    }
    chu("%lld",sum);
    return 0;
}
/*
5
2 2 2 0 2 
10
0 1 2 1 2 2 1 0 1 2 
3 1 1 1
3 2 1 1 
10 1 1 1 1 1 1 1 1 1 1 
*/

T4:给你长度n的序列,每过1时刻,a(i+1)=max(ai,a(i+1)),同时发生。给出q个询问,[l,r,t],求t时刻[l,r]区间的数的和值。(q,n<=2e5)

30tps:暴力枚举所有时刻的序列状态。优化:
按照t排序询问,当存在某个时刻,这个序列一个数也不再更新,这个序列以后的时刻一定不再会被更新。
30+6tps:当l==r,发现如果把每个数向前面第一个>他的连边,那么答案就是他的(pos-t)级祖先内的ai最大的数,倍增跳就行。

点击查看代码




#include<bits/stdc++.h>
using namespace std;
#define _f(i,a,b) for(register int i=a;i<=b;++i)
#define f_(i,a,b) for(register int i=a;i>=b;--i)
#define chu printf
#define ll long long
#define ull unsigned long long
inline ll re()
{
    ll x=0,h=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')h=-1;
        ch=getchar();
    }
    while(ch<='9'&&ch>='0')
    {
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*h;
}
const int N=2e5+10;
ll sta[2000+10][2000+10];//时间,状态
int bz[N][21],dd[N],top;//19就够了
int n,q,val[N];
struct Que
{
    int t,l,r,id;
    bool operator<(const Que&U)const
    {
        return t<U.t;
    }
}qr[N];
ll ans[N];
inline void deal_easy()
{
   _f(i,1,n)
   sta[0][i]=re();
   _f(t,1,n)//记录时间
   {
       _f(i,1,n)//看变换
       sta[t][i]=max(sta[t-1][i-1],sta[t-1][i]);
   }
   _f(t,0,n)
   _f(i,1,n)
   sta[t][i]=sta[t][i-1]+sta[t][i];
   _f(i,1,q)
   {
       int t=re(),l=re(),r=re();
        chu("%lld\n",sta[t][r]-sta[t][l-1]);
   }
}
inline int lowerbound(int vl)
{
    int l=1,r=top;int as=1;
    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(val[dd[mid]]>vl)
        {
            as=mid;l=mid+1;
        }
        else r=mid-1;
    }
    return as;
}
inline void deal_only()
{

     dd[++top]=1;
    _f(i,0,19)bz[1][i]=1;
    _f(i,2,n)
    {
        if(val[dd[1]]<=val[i])
        {
           // chu("i:%d(%d\n",i,i);
            _f(j,0,19)bz[i][j]=i;
        }
        else
        {
            int pos=lowerbound(val[i]);
            bz[i][0]=dd[pos];
         //   _f(j,1,top)chu("%d ",dd[j]);chu("\n");
           // chu("i:%d(%d\n",i,dd[pos]);
        }
        while(top>0&&val[dd[top]]<=val[i])--top;
        dd[++top]=i;
    }
    _f(j,1,19)
    _f(i,1,n)
    bz[i][j]=bz[bz[i][j-1]][j-1];//chu("here:%d\n",bz[i][j]);
  
    _f(i,1,q)
    {
        //t,l,r
        int ps=qr[i].l,dc=qr[i].t;
        int lj=0;int prepos=ps;
        f_(j,19,0)
        {
            int vad=prepos-bz[prepos][j];
            if(vad+lj<=dc)
            {
                prepos=bz[prepos][j];lj+=vad;
            }
        }
        chu("%d\n",val[prepos]);
    }
}
int main()
{
    freopen("o.in","r",stdin);
   freopen("o.out","w",stdout);
   n=re(),q=re();
   if(n<=2000&&q<=2000)
   {
       deal_easy();
       return 0;
   } 
    int onlylr=1;
    _f(i,1,n)val[i]=re();
    _f(i,1,q)
    {
        qr[i].t=re(),qr[i].l=re(),qr[i].r=re();qr[i].id=i;
        if(qr[i].l!=qr[i].r)onlylr=0;
    }
    if(onlylr)
    {
        //chu("df\n");
        deal_only();
        return 0;
    }
   // chu("here\n");
   sort(qr+1,qr+1+q);
   int tot,fl=0,now=0;
   _f(ii,1,q)
   {
       int t=qr[ii].t,l=qr[ii].l,r=qr[ii].r;
       while(now<t&&(!fl))
       {
           ++now;tot=0;
           _f(i,1,n)dd[i]=val[i];
           _f(i,2,n)
           {
               if(dd[i-1]>val[i])
               val[i]=dd[i-1],tot=1;
           }
           if(tot==0)fl=1;
       }
       _f(j,l,r)
       ans[qr[ii].id]+=(ll)val[j];
   }
    _f(i,1,q)
    chu("%lld\n",ans[i]);
    return 0;
}
/*20 20
2 1 2 2 1 1 1 1 2 2 2 1 2 1 1 2 1 2 1 1
1 1 14
2 3 18
4 10 15
8 2 17
9 20 20
4 8 19
7 2 20
11 1 5
13 2 8
20 1 20
2 12 15
7 1 14
12 7 18
14 2 17
9 19 20
12 12 12
6 2 15
11 2 15
19 12 17
4 1 20

25
30
12
32
2
24
38
10
14
40
8
28
24
32
4
2
28
28
12
40

5 5
9 3 2 6 5
2 1 1
2 2 2 
2 3 3 
2 4 4 
2 5 5 
*/

90tps:延续倍增思路,每个点在一个固定的区段内一定是一个固定的值,那么我们单调队列维护这个数前面>这个数的值和位置,维护不同时刻的值对应作用区间,主席树下标就代表时间,维护一下这个覆盖的值,为了单点修改可以影响区间,所以用一个差分。

点击查看代码




#include<bits/stdc++.h>
using namespace std;
#define _f(i,a,b) for(register int i=a;i<=b;++i)
#define f_(i,a,b) for(register int i=a;i>=b;--i)
#define chu printf
#define ll long long
#define ull unsigned long long
inline ll re()
{
    ll x=0,h=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')h=-1;
        ch=getchar();
    }
    while(ch<='9'&&ch>='0')
    {
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*h;
}
const int N=2e5+10;;//时间,状态
int bz[N][21],dd[N],top;//19就够了
int n,q,val[N];
ll ans[N];
struct Que
{
    int t,l,r,id;
}qr[N];
struct TREE
{
	int ls,rs;
	ll sum;
}t[N*50];
int tot,root[N],sta[N];
// #define ls(rt) t[rt].ls
// #define rs(rt) t[rt].rs
inline void Build(int&rt,int l,int r)
{
	rt=++tot;
	if(l==r)return;
	int mid=(l+r)>>1;
	Build(t[rt].ls,l,mid);
	Build(t[rt].rs,mid+1,r);
}
inline void Up(int rt)
{
	t[rt].sum=t[t[rt].ls].sum+t[t[rt].rs].sum;
}
inline void Update(int&rt,int pre,int l,int r,int pos,ll vl)
{
	rt=++tot;
	t[rt]=t[pre];
	if(l==r)
	{
		t[rt].sum+=vl;return;
	}
	int mid=(l+r)>>1;
	if(pos<=mid)Update(t[rt].ls,t[pre].ls,l,mid,pos,vl);
	else Update(t[rt].rs,t[pre].rs,mid+1,r,pos,vl);
	Up(rt);
}
inline ll Query(int rt,int pre,int l,int r,int L,int R)
{
	if(L<=l&&r<=R)
	{
		return t[rt].sum-t[pre].sum;
	}
	int mid=(l+r)>>1;ll res=0;
	if(L<=mid)
	res+=Query(t[rt].ls,t[pre].ls,l,mid,L,R);
	if(R>mid)
	res+=Query(t[rt].rs,t[pre].rs,mid+1,r,L,R);
	return res;
}
inline void deal_tree()
{
	Build(root[0],1,n+1);
	_f(i,1,n)
	{
		while(top>0&&val[sta[top]]<=val[i])--top;
		sta[++top]=i;
		Update(root[i],root[i-1],1,n+1,1,val[i]);
		_f(j,1,top-1)
		{
			Update(root[i],root[i],1,n+1,i-sta[j]+1,val[sta[j]]-val[sta[j+1]]);
		}
	}
	_f(i,1,q)
	{
		int t=qr[i].t,l=qr[i].l,r=qr[i].r;
		ans[qr[i].id]=Query(root[r],root[l-1],1,n+1,1,t+1);
	}
	_f(i,1,q)chu("%lld\n",ans[i]);
}
inline int lowerbound(int vl)
{
    int l=1,r=top;int as=1;
    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(val[dd[mid]]>vl)
        {
            as=mid;l=mid+1;
        }
        else r=mid-1;
    }
    return as;
}
inline void deal_only()
{

     dd[++top]=1;
    _f(i,0,19)bz[1][i]=1;
    _f(i,2,n)
    {
        if(val[dd[1]]<=val[i])
        {
           // chu("i:%d(%d\n",i,i);
            _f(j,0,19)bz[i][j]=i;
        }
        else
        {
            int pos=lowerbound(val[i]);
            bz[i][0]=dd[pos];
         //   _f(j,1,top)chu("%d ",dd[j]);chu("\n");
           // chu("i:%d(%d\n",i,dd[pos]);
        }
        while(top>0&&val[dd[top]]<=val[i])--top;
        dd[++top]=i;
    }
    _f(j,1,19)
    _f(i,1,n)
    bz[i][j]=bz[bz[i][j-1]][j-1];//chu("here:%d\n",bz[i][j]);
    _f(i,1,q)
    {
        //t,l,r
        int ps=qr[i].l,dc=qr[i].t;
        int lj=0;int prepos=ps;
        f_(j,19,0)
        {
            int vad=prepos-bz[prepos][j];
            if(vad+lj<=dc)
            {
                prepos=bz[prepos][j];lj+=vad;
            }
        }
        chu("%d\n",val[prepos]);
    }
}
int main()
{
   freopen("o.in","r",stdin);
  freopen("o.out","w",stdout);
   n=re(),q=re();
    int onlylr=1;
    _f(i,1,n)val[i]=re();
    _f(i,1,q)
    {
        qr[i].t=re(),qr[i].l=re(),qr[i].r=re();qr[i].id=i;
        if(qr[i].l!=qr[i].r)onlylr=0;
    }
    if(onlylr)
    {
        deal_only();
        return 0;
    }
	deal_tree();
    return 0;
}
/*
10 10
3 1 4 1 5 9 2 6 5 3
1 1 6
2 8 10
4 2 7
8 3 3
6 1 10
3 2 8
5 1 9
7 4 5
9 7 9
10 10 10
*/

posted on 2022-09-15 17:19  HZOI-曹蓉  阅读(46)  评论(0编辑  收藏  举报