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
*/