noip模拟78[小慌]
noip模拟78 solutions
怎么说还是没有考好
有了依赖随机性的算法却不敢写
有了啥B贪心也不敢写
有了一半正解但是没有办法码出来
还是我代码能力比较低下
马上就要\(CSP\)了,不知道会不会一直这样下去
希望接下来可以考的好一些......
T1 F
这个完全可以直接枚举的,\(\mathcal{O(n^2)}\)
AC_code
#include<bits/stdc++.h>
using namespace std;
#define oj
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int N=2005;
int n,a[N],b[N];
int lsh[N],lh;
int buc[N],fb[N];
int ans[N];
unordered_map<int,int> mp;
signed main(){
#ifdef oj
freopen("f.in","r",stdin);
freopen("f.out","w",stdout);
#endif
scanf("%d",&n);
fo(i,1,n)scanf("%d",&a[i]),lsh[i]=a[i];lh=n;
fo(i,1,n)scanf("%d",&b[i]);
sort(lsh+1,lsh+n+1);
lh=unique(lsh+1,lsh+lh+1)-lsh-1;
fo(i,1,lh)mp.insert(make_pair(lsh[i],i));
fo(i,2,n){
unordered_map<int,int>::iterator it=mp.find(a[i]);
buc[it->second]++;fb[it->second]++;
}
int now,ys;
bool flag;
fo(i,1,n){
now=a[1]^b[i];
flag=true;
fo(j,1,n){
if(i==j)continue;
ys=now^b[j];
unordered_map<int,int>::iterator it=mp.find(ys);
if(it==mp.end()){flag=false;break;}
if(!buc[it->second]){flag=false;break;}
buc[it->second]--;
}
if(flag)ans[++ans[0]]=now;
fo(j,1,lh)buc[j]=fb[j];
}
if(ans[0]){
sort(ans+1,ans+ans[0]+1);
ans[0]=unique(ans+1,ans+ans[0]+1)-ans-1;
}
printf("%d\n",ans[0]);
fo(i,1,ans[0])printf("%d\n",ans[i]);
return 0;
}
T2 S
首先有一个这类交换问题通用的结论:
每次选择两个相邻球的交换,想要交换成另一个序列,交换次数最少是逆序对数
直接用这个结论\(DP\)就行了
设\(dp[i][j][k][0/1/2]\)表示当前放了\(i\)个红球,\(j\)个绿球,\(k\)个蓝球,最后一个是啥颜色的最少逆序对数
也就是最少的交换次数
为什么要记录最后一个是啥,因为相邻颜色是不可以相同的
到时候直接枚举下一个选啥,计算多出来的逆序对数就好了
因为要保证最小步数,所以相同颜色的顺序一定不会变,我只需要知道有多少其他颜色的应该放在前面但是放在了后面就行了
AC_code
#include<bits/stdc++.h>
using namespace std;
#define oj
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int N=405;
int n,xl[N];
char a[N];
int buc[5],st[5][N];
int dp[N/2][N/2][N/2][3],ans;
signed main(){
#ifdef oj
freopen("s.in","r",stdin);
freopen("s.out","w",stdout);
#endif
scanf("%d",&n);
scanf("%s",a+1);
fo(i,1,n){
if(a[i]=='R')xl[i]=0;
if(a[i]=='G')xl[i]=1;
if(a[i]=='Y')xl[i]=2;
buc[xl[i]]++;
st[xl[i]][++st[xl[i]][0]]=i;
}
if(buc[1]>(n+1>>1)||buc[2]>(n+1>>1)||buc[0]>(n+1>>1)){
printf("-1");return 0;
}
memset(dp,0x3f,sizeof(dp));
dp[1][0][0][0]=st[0][1]-1;
dp[0][1][0][1]=st[1][1]-1;
dp[0][0][1][2]=st[2][1]-1;
fo(i,0,buc[0]){
fo(j,0,buc[1]){
fo(k,0,buc[2]){
if(i==1&&j==0&&k==0)continue;
if(i==0&&j==1&&k==0)continue;
if(i==0&&j==0&&k==1)continue;
if(i>0){
int p1=lower_bound(st[1]+1,st[1]+st[1][0]+1,st[0][i])-st[1]-1;
int p2=lower_bound(st[2]+1,st[2]+st[2][0]+1,st[0][i])-st[2]-1;
int tmp=(p1-j>0?p1-j:0)+(p2-k>0?p2-k:0);
dp[i][j][k][0]=min(dp[i][j][k][0],min(dp[i-1][j][k][1],dp[i-1][j][k][2])+tmp);
}
if(j>0){
int p1=lower_bound(st[0]+1,st[0]+st[0][0]+1,st[1][j])-st[0]-1;
int p2=lower_bound(st[2]+1,st[2]+st[2][0]+1,st[1][j])-st[2]-1;
int tmp=(p1-i>0?p1-i:0)+(p2-k>0?p2-k:0);
dp[i][j][k][1]=min(dp[i][j][k][1],min(dp[i][j-1][k][0],dp[i][j-1][k][2])+tmp);
}
if(k>0){
int p1=lower_bound(st[1]+1,st[1]+st[1][0]+1,st[2][k])-st[1]-1;
int p2=lower_bound(st[0]+1,st[0]+st[0][0]+1,st[2][k])-st[0]-1;
int tmp=(p1-j>0?p1-j:0)+(p2-i>0?p2-i:0);
dp[i][j][k][2]=min(dp[i][j][k][2],min(dp[i][j][k-1][1],dp[i][j][k-1][0])+tmp);
}
}
}
}
ans=min(dp[buc[0]][buc[1]][buc[2]][0],min(dp[buc[0]][buc[1]][buc[2]][1],dp[buc[0]][buc[1]][buc[2]][2]));
printf("%d",ans);
return 0;
}
T3 Y
竟然是\(atcoder\)的原题,真的是我做题过于少了
首先这个题要求的答案要保证\(B\)是互不相同的,如果\(C\)序列中最小的不是\(0\),那么整体减一答案不变
所以我们最后答案的\(C\)序列中必须包含\(1\)
其次,答案要求的其实就是所有人在自己的球中选一个,总的方案数
这样的话,我们就有\(DP\)的转移目标了
我们先不限制\(C\)中有没有\(0\)
\(DP\)设计极其扭曲,\(f[i][0/1]\)表示当前到第\(i\)位
\(0\)表示当前这个人选前面的人给他的球,前\(i\)个人的方案数
\(1\)表示当前这个人选自己的球,前\(i-1\)个人的方案数
为什么定义是这样的,因为我们要根据球的来源来算方案数,每个人原有的这些球是独立的
所以这样就可以分层去转移了,也就可以设计方程了
注意这里是环,要钦定\(1\)的选择,并且最后的答案只能是这个选择
设\(pr1(n)=1+2+3+...+n=\frac{n(n+1)}{2}\)
设\(pr2(n)=1^2+2^2+3^2+...+n^2=\sum\limits_{i=1}^{n}i^2=\frac{n(n+1)(2*n+1)}{6}\)
\(f_{i+1,0}+=f_{i,0}*pr1(a_i)\)
\(f_{i+1,0}+=f_{i,1}*pr2(a_i)\)
\(f_{i+1,1}+=f_{i,0}*(a_i+1)\)
\(f_{i+1,1}+=f_{i,1}*pr1(a_i)\)
最后的时候从\(n\)转移到\(1\),答案就是钦定的那个值\(-1\)
但是我们此时方案是重复的,所以要把没有\(0\)的方案减去,直接限制转移的时候不能有\(0\)就好了
AC_code
#include<bits/stdc++.h>
using namespace std;
#define oj
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int N=1e6+5;
const int mod=1e9+7;
int n,a[N],ans;
int f[N][2],iv2,iv6;
int ksm(int x,int y){
int ret=1;
while(y){
if(y&1)ret=ret*x%mod;
x=x*x%mod;y>>=1;
}return ret;
}
int pr1(int x){return x*(x+1)%mod*iv2%mod;}
int pr2(int x){return x*(x+1)%mod*(2*x+1)%mod*iv6%mod;}
int dp(int x,int y){
memset(f,0,sizeof(f));
f[1][1]=x;f[1][0]=x^1;
fo(i,1,n){
int t=i%n+1;
if(y){
f[t][1]=(f[t][1]+f[i][1]*pr1(a[i]-1))%mod;
f[t][1]=(f[t][1]+f[i][0]*a[i])%mod;
}
else {
f[t][1]=(f[t][1]+f[i][1]*pr1(a[i]))%mod;
f[t][1]=(f[t][1]+f[i][0]*(a[i]+1))%mod;
}
f[t][0]=(f[t][0]+f[i][0]*pr1(a[i]))%mod;
f[t][0]=(f[t][0]+f[i][1]*((a[i]*pr1(a[i])-pr2(a[i])+mod)%mod))%mod;
}
return ((x?f[1][1]:f[1][0])+mod-1)%mod;
}
signed main(){
#ifdef oj
freopen("y.in","r",stdin);
freopen("y.out","w",stdout);
#endif
scanf("%lld",&n);
fo(i,1,n)scanf("%lld",&a[i]);
iv2=ksm(2,mod-2);
iv6=ksm(6,mod-2);
ans=(dp(1,0)+dp(0,0)-dp(1,1)-dp(0,1)+2*mod)%mod;
printf("%lld",ans);
}
T4 O
这个我是\(cao\)过去的,因为出题人精心构造递增序列...
AC_code
#include<bits/stdc++.h>
using namespace std;
#define oj
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int N=2e5+5;
int n,q,a[N];
struct node{
int t,l,r,id;
node(){}
bool operator < (node x)const{
return t<x.t;
}
}qus[N];
int ans[N];
bool fl1=true;
int st[N][20],lg[N];
int get(int l,int r){
int tmp=lg[r-l+1];
return max(st[l][tmp],st[r-(1<<tmp)+1][tmp]);
}
int sta[N],top;
vector<pair<int,int> > vec[N];
struct XDS{
#define ls x<<1
#define rs x<<1|1
int sum[N*4];
void pushup(int x){sum[x]=sum[ls]+sum[rs];}
void build(int x,int l,int r){
if(l==r)return sum[x]=a[l],void();
int mid=l+r>>1;
build(ls,l,mid);
build(rs,mid+1,r);
pushup(x);return ;
}
void ins(int x,int l,int r,int pos,int v){
if(l==r)return sum[x]=v,void();
int mid=l+r>>1;
if(pos<=mid)ins(ls,l,mid,pos,v);
else ins(rs,mid+1,r,pos,v);
pushup(x);return ;
}
int query(int x,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr)return sum[x];
int mid=l+r>>1,ret=0;
if(ql<=mid)ret+=query(ls,l,mid,ql,qr);
if(qr>mid)ret+=query(rs,mid+1,r,ql,qr);
return ret;
}
#undef ls
#undef rs
}xds;
signed main(){
#ifdef oj
freopen("o.in","r",stdin);
freopen("o.out","w",stdout);
#endif
scanf("%lld%lld",&n,&q);
fo(i,1,n)scanf("%lld",&a[i]);
fo(i,1,q){
scanf("%lld%lld%lld",&qus[i].t,&qus[i].l,&qus[i].r);
qus[i].id=i;
if(qus[i].l!=qus[i].r)fl1=false;
}
xds.build(1,1,n);
sort(qus+1,qus+q+1);
if(fl1){
lg[0]=-1;fo(i,1,n)lg[i]=lg[i>>1]+1;
fu(i,n,1){
st[i][0]=a[i];
//cout<<st[i][0]<<endl;
for(int j=1;j<=19&&i+(1<<j)-1<=n;j++)
st[i][j]=max(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}
fo(i,1,q)ans[qus[i].id]=get(max(qus[i].l-qus[i].t,1ll),qus[i].r);
fo(i,1,q)printf("%lld\n",ans[i]);
return 0;
}
fo(i,1,n){
while(top&&a[sta[top]]<=a[i])top--;
sta[++top]=i;
fo(j,1,top-1)vec[i-sta[j]].push_back(make_pair(i,a[sta[j]]));
}
fo(i,1,q){
if(qus[i].t!=qus[i-1].t){
fo(j,qus[i-1].t+1,qus[i].t){
for(auto x:vec[j])xds.ins(1,1,n,x.first,x.second);
}
}
ans[qus[i].id]=xds.query(1,1,n,qus[i].l,qus[i].r);
}
fo(i,1,q)printf("%lld\n",ans[i]);
}