noip模拟74
A. 自然数
线段树二分在之前的题目中出现过,但是我是用别的方法写的.
所以这个题在我这里就死了.
固定左端点应该是能想到的,因为这样的套路很多,但是自己没想到,不应该.
A_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS {
#define ll long long
#define ull unsigned ll
#define lf long double
#define lbt(x) (x&(-x))
#define mp(x,y) make_pair(x,y)
#define lb lower_bound
#define ub upper_bound
#define Fill(x,y) memset(x,y,sizeof x)
#define Copy(x,y) memcpy(x,y,sizeof x)
#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
inline ll read() {
ll w=0; bool cit=1; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
while(isdigit(ch)) w=(w<<3)+(w<<1)+(ch^48),ch=getchar();
return cit?w:-w;
}
} using namespace BSS;
#define ls (x<<1)
#define rs (x<<1|1)
const ll N=1e6+21,W=2e5+21;
ll m,n,ans;
ll vis[N],val[N],lst[N],nxt[N];
struct I { ll sum,lzy,maxw; } tr[N<<2];
auto getval=[](ll
x,ll w,ll l,ll r){
tr[x].sum=(r-l+1)*w,tr[x].lzy=w,tr[x].maxw=w;
};
auto spread=[](ll x,ll l,ll r){
ll &lzy=tr[x].lzy,mid=(l+r)>>1;
if(~lzy) getval(ls,lzy,l,mid),getval(rs,lzy,mid+1,r),lzy=-1;
};
auto pushup=[](ll x){
tr[x].sum=tr[ls].sum+tr[rs].sum;
tr[x].maxw=max(tr[ls].maxw,tr[rs].maxw);
};
void change(ll x,ll l,ll r,ll ql,ll qr,ll w){
if(l>=ql and r<=qr) return getval(x,w,l,r),void();
ll mid=(l+r)>>1; spread(x,l,r);
if(ql<=mid) change(ls,l,mid,ql,qr,w);
if(qr>mid) change(rs,mid+1,r,ql,qr,w);
pushup(x);
}
ll qsum(ll x,ll l,ll r,ll ql,ll qr){
if(l>=ql and r<=qr) return tr[x].sum;
ll mid=(l+r)>>1,res=0; spread(x,l,r);
if(ql<=mid) res+=qsum(ls,l,mid,ql,qr);
if(qr>mid) res+=qsum(rs,mid+1,r,ql,qr);
pushup(x); return res;
}
ll qmax(ll x,ll l,ll r,ll ql,ll qr){
if(ql>qr) return -1;
if(l>=ql and r<=qr) return tr[x].maxw;
ll mid=(l+r)>>1,res=0; spread(x,l,r);
if(ql<=mid) res=max(res,qmax(ls,l,mid,ql,qr));
if(qr>mid) res=max(res,qmax(rs,mid+1,r,ql,qr));
pushup(x); return res;
}
ll qpos(ll x,ll l,ll r,ll ql,ll qr,ll w){
if(l==r) return tr[x].maxw>=w ? l : -1;
ll mid=(l+r)>>1,res; spread(x,l,r);
if(l>=ql and r<=qr){
if(tr[ls].maxw>=w) res=qpos(ls,l,mid,ql,qr,w);
else res=qpos(rs,mid+1,r,ql,qr,w);
pushup(x); return res;
}
if(ql<=mid and tr[ls].maxw>w) res=qpos(ls,l,mid,ql,qr,w);
else res=qpos(rs,mid+1,r,ql,qr,w);
pushup(x); return res;
}
void build(ll x,ll l,ll r){
tr[x].lzy=-1;
if(l==r) return ; ll mid=(l+r)>>1;
build(ls,l,mid),build(rs,mid+1,r);
}
signed main(){
File(mex);
n=read(); ll now=0,x,y;
for(ll i=1;i<=n;i++) val[i]=read();
for(ll i=1;i<=n;i++){
if(val[i]>n) { change(1,1,n,i,i,now); continue; }
if(vis[val[i]]) lst[i]=vis[val[i]],nxt[vis[val[i]]]=i;
vis[val[i]]=i; while(vis[now]) now++; change(1,1,n,i,i,now);
}
for(ll i=n;i>=1;i--){
if(val[i]>n) continue;
if(!nxt[i]) nxt[i]=n+1;
}
for(ll i=1;i<=n;i++){
ans+=qsum(1,1,n,i,n);
if(val[i]>n or qmax(1,1,n,i+1,n)<val[i]) continue;
now=qpos(1,1,n,i+1,n,val[i]);
if(now>0) change(1,1,n,now,nxt[i]-1,val[i]);
}
printf("%lld\n",ans),exit(0);
}
B. 钱仓
签到题,贪心乱写.
由于博主比较智障,直接糊了个线段树.
B_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS {
#define ll long long
#define ull unsigned ll
#define lf long double
#define lbt(x) (x&(-x))
#define mp(x,y) make_pair(x,y)
#define lb lower_bound
#define ub upper_bound
#define Fill(x,y) memset(x,y,sizeof x)
#define Copy(x,y) memcpy(x,y,sizeof x)
#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
inline ll read() {
ll w=0; bool cit=1; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
while(isdigit(ch)) w=(w<<3)+(w<<1)+(ch^48),ch=getchar();
return cit?w:-w;
}
} using namespace BSS;
#define ls x<<1
#define rs x<<1|1
const ll N=2e5+21,inf=1e15;
ll m,n,pc,ans,minpos,minval;
ll o[N];
struct I { ll w,c,len,lc,llen; } tr[N<<2];
auto getval=[](ll x,ll c,ll len)->void{
tr[x].c+=c,tr[x].len+=len,tr[x].w=tr[x].len-tr[x].c;
tr[x].lc+=c,tr[x].llen+=len;
};
void update(ll x,ll l,ll r,ll ql,ll qr,ll c,ll len){
if(l>=ql and r<=qr) return getval(x,c,len)/*,cout<<l<<' '<<r<<" "<<tr[x].c<<' '<<tr[x].w<<endl*/,void();
// 让 len-c 时刻都 >= 0 ,所以维护最小值,如果存在最小值小于 0,那么不行.
ll mid=(l+r)>>1;
getval(ls,tr[x].lc,tr[x].llen),getval(rs,tr[x].lc,tr[x].llen);
tr[x].lc=0,tr[x].llen=0;
if(ql<=mid) update(ls,l,mid,ql,qr,c,len);
if(qr>mid) update(rs,mid+1,r,ql,qr,c,len);
ll y= (tr[ls].w<tr[rs].w ? ls : rs);
tr[x].w=tr[y].w,tr[x].c=tr[y].c,tr[x].len=tr[y].len;
// cout<<l<<' '<<r<<' '<<tr[x].w<<' '<<tr[ls].w<<' '<<tr[rs].w<<endl;
}
signed main(){
File(barn);
n=read(),m=n<<1,minval=inf; ll flag=0,res;
for(ll i=1;i<=n;i++){
o[i]=read(),o[i+n]=o[i],flag|=(o[i]==0);
}
for(ll i=m;i>=n+1;i--) pc+=o[i],update(1,1,m,i,i,pc,m-i+1);
for(ll i=1;i<=n;i++) update(1,1,m,i,i,-inf,inf);
if(!flag) puts("0"),exit(0); minval=tr[1].w,minpos=m;
for(ll i=n;i>=2;i--){
update(1,1,m,i+n,i+n,-inf,inf);
ll r=i+n-1,l=i-1;
update(1,1,m,l,r,-o[r+1],-1),update(1,1,m,i,i,pc,n);
if(tr[1].w>minval) minval=tr[1].w,minpos=i+n-1;
}
// cout<<minval<<' '<<minpos<<endl;
for(ll i=minpos,j=minpos;i>=minpos-n+1;i--){
if(!o[i]){
while(!o[j]) j--;
o[i]++,o[j]--,ans+=(i-j)*(i-j);
}
else j=min(j,i-1);
}
printf("%lld\n",ans),exit(0);
}
C. 游戏
很明显应该是 \(dp\),很明显又应该是矩阵优化.
其实列个式子好像就很容易出来了,感觉并不是那种完全做不出来的题目。
C_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS {
#define ll long long
#define ull unsigned ll
#define lf long double
#define lbt(x) (x&(-x))
#define mp(x,y) make_pair(x,y)
#define lb lower_bound
#define ub upper_bound
#define Fill(x,y) memset(x,y,sizeof x)
#define Copy(x,y) memcpy(x,y,sizeof x)
#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
inline ll read() {
ll w=0; bool cit=1; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
while(isdigit(ch)) w=(w<<3)+(w<<1)+(ch^48),ch=getchar();
return cit?w:-w;
}
} using namespace BSS;
const ll mod=1e9+7;
ll n,p,q,m,Ts;
ll f[3],g[3][3],g1[3][3],g2[3][3];
auto ksm=[](ll a,ll b,ll c)->ll{
ll res=1; a%=c;
for(;b;b>>=1,a=a*a%c) if(b&1) res=res*a%c;
return res%c;
};
inline void mul(){
ll c[3]={0};
for(ll j=1;j<=2;j++){
for(ll k=1;k<=2;k++)
c[j]=(c[j]+f[k]*g[k][j]%mod)%mod;
}
Copy(f,c);
}
inline void mulself(){
ll c[3][3]={0};
for(ll i=1;i<=2;i++){
for(ll j=1;j<=2;j++)
for(ll k=1;k<=2;k++)
c[i][j]=(c[i][j]+g[i][k]*g[k][j]%mod)%mod;
}
Copy(g,c);
}
inline void mulmore(){
ll c[3]={0};
for(ll j=1;j<=2;j++){
for(ll k=1;k<=2;k++)
c[j]=(c[j]+f[k]*g2[k][j]%mod)%mod;
}
Copy(f,c);
}
signed main(){
File(game);
Ts=read();
while(Ts--){
Fill(f,0),Fill(g,0);
ll x=ksm(1e8,mod-2,mod); f[2]=1;
n=read(),p=read()%mod*x%mod,q=read()%mod*x%mod;
x=ksm(1-p*q%mod+mod,mod-2,mod);
g1[1][1]=p*(1-q+mod)%mod*x%mod,g1[2][1]=(1-p+mod)*x%mod;
g1[1][2]=(1-q+mod)*x%mod,g1[2][2]=q*(1-p+mod)%mod*x%mod;
x=ksm(1-(1-p+mod)%mod*(1-q+mod)%mod+mod,mod-2,mod);
g2[1][1]=(1-p+mod)*q%mod*x%mod,g2[2][1]=p*x%mod;
g2[1][2]=q*x%mod,g2[2][2]=(1-q+mod)*p%mod*x%mod;
for(ll i=1;i<=2;i++){
for(ll j=1;j<=2;j++)
for(ll k=1;k<=2;k++)
g[i][j]=(g[i][j]+g2[i][k]*g1[k][j]%mod)%mod;
}
m=n>>1; for(;m;m>>=1,mulself()) if(m&1) mul();
if(n&1) mulmore();
printf("%lld\n",f[1]);
}
exit(0);
}
D. Sanrd
容易发现一个性质,对于每一对 \(LIS\) 和 \(LDS\),最多都只有一个交点.
所以可以选择统计一个 \(LIS\) 中每个点出现在 \(LDS\) 的次数,来判断这个 \(LIS\) 是否合法.
关于统计次数,正着做一遍 \(BIT\) 反着做一遍 \(BIT\),然后乘法原理即可.
设 \(f_i\) 表示 \(i\) 这个点在 \(LDS\) 中出现的次数,\(alls\) 表示所有 \(LDS\) 的个数.
所以这个 \(LIS\) 合法的条件就是 \(\sum f_i\le alls\).
于是随便选一个 \(LIS\) 删掉,然后再做一遍 \(LDS\) 就可以了.
D_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS{
#define ll long long
#define lf double
#define ull unsigned ll
#define mp make_pair
#define lb lower_bound
#define ub upper_bound
#define lbt(x) ((x)&(-(x)))
#define Fill(x,y) memset(x,y,sizeof(x))
#define Copy(x,y) memcpy(x,y,sizeof(x))
#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
auto read=[]()->ll{
ll w=0; bool cit=1; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
while(isdigit(ch)) w=(w<<3)+(w<<1)+(ch^48),ch=getchar();
return cit?w:(-w);
};
} using namespace BSS;
const ll N=5e5+21,mod=998244353,inf=1e15;
ll m,n,lis,lds,alls;
ll f[N],val[N],ans[N],vis[N],pre[N],ld[N];
pair<ll,ll> ds[N];
struct I { ll a,id,ids; ll g[2][2]; } is[N];
struct FinI {
pair<ll,ll> res; pair<ll,ll> c[N<<1];
inline void update(ll x,ll w,ll wc){
for(;x<=n;x+=lbt(x)){
if(c[x].first<w) c[x].first=w,c[x].second=0;
(c[x].second+=wc*(w==c[x].first))%=mod;
}
}
inline pair<ll,ll> query(ll x){
res.first=0,res.second=0;
for(;x;x&=x-1){
if(c[x].first>res.first) res.first=c[x].first,res.second=0;
(res.second+=c[x].second*(c[x].first==res.first))%=mod;
}
return res;
}
inline void clr(){ Fill(c,0); }
}A;
struct FinII {
ll res; I c[N<<1];
inline void change(I &x,I y){
if(!y.ids) return ;
if(x.a<y.a) x.a=y.a,x.ids=0;
if(x.ids==2) return ;
if(x.a==y.a){
if(y.ids==2){
x.g[0][0]=y.id,x.g[0][1]=y.g[0][1];
x.g[1][0]=y.id,x.g[1][1]=y.g[1][1];
return x.ids=2,void();
}
if(!x.ids){
x.g[0][0]=y.id,x.g[0][1]=y.g[0][1];
return x.ids=1,void();
}
if(y.g[0][1]==x.g[0][1]) return ;
x.ids=2,x.g[1][0]=y.id,x.g[1][1]=y.g[0][1];
}
}
inline void update(ll x,I w){
for(;x<=n;x+=lbt(x)) change(c[x],w);
}
inline void query(ll u,ll v){
I &x=is[v];
for(I y;u;u&=u-1){
y=c[u];
if(!y.ids) continue;
if(x.a<y.a) x.a=y.a,x.ids=0;
if(x.ids==2) continue;
if(x.a==y.a){
if(y.ids==2){
x.g[0][0]=y.g[0][0],x.g[0][1]=y.g[0][1];
x.g[1][0]=y.g[1][0],x.g[1][1]=y.g[1][1];
x.ids=2; continue;
}
if(!x.ids){
x.g[0][0]=y.g[0][0],x.g[0][1]=y.g[0][1];
x.ids=1; continue;
}
if(y.g[0][1]==x.g[0][1]) continue;
x.ids=2,x.g[1][0]=y.g[0][0],x.g[1][1]=y.g[0][1];
}
}
}
}B;
struct FinIII {
ll c[N<<1];
inline void change(ll &x,ll y){ if(ld[x]<ld[y]) x=y; }
inline void update(ll x,ll w){ for(;x<=n;x+=lbt(x)) change(c[x],w); }
inline void query(ll x,ll y){ for(;x;x&=x-1) change(pre[y],c[x]); }
}C;
signed main(){
File(sanrd);
n=read(); pair<ll,ll> res; ll u,v,w;
for(ll i=1;i<=n;i++) val[i]=n-read()+1,is[i].id=i;
for(ll i=1;i<=n;i++){
ds[i]=A.query(val[i]),ds[i].first++;
if(ds[i].first==1) ds[i].second=1;
lds=max(lds,ds[i].first);
A.update(val[i],ds[i].first,ds[i].second);
}
A.clr();
for(ll i=n;i>=1;i--){
val[i]=n-val[i]+1,res=A.query(val[i]),res.first++;
if(res.first==1) res.second=1;
if(res.first+ds[i].first==lds+1) f[i]=res.second*ds[i].second%mod;
A.update(val[i],res.first,res.second);
}
for(ll i=1;i<=n;i++)
alls=(alls+ds[i].second*(ds[i].first==lds))%mod;
for(ll i=1;i<=n;i++){
B.query(val[i],i); I &x=is[i]; x.a++;
if(x.a==1) x.ids=1;
(x.g[0][1]+=f[i])%=mod,(x.g[1][1]+=f[i])%=mod;
B.update(val[i],x),lis=max(lis,x.a);
// cout<<lis<<' '<<is[i].a<<" "<<is[i].ids<<' '<<is[i].g[0][0]<<' '<<is[i].g[1][0]<<endl;
}
u=0;
for(ll i=1;i<=n;i++){
if(is[i].a==lis){
if(is[i].ids>=1 and is[i].g[0][1]!=alls){ u=i,v=is[i].g[0][0],w=is[i].g[0][1]; break; }
if(is[i].ids==2 and is[i].g[1][1]!=alls){ u=i,v=is[i].g[1][0],w=is[i].g[1][1]; break; }
}
}
if(!u) puts("-1"),exit(0);
for(ll i=lis;i>=1;i--){
vis[u]=1,ans[i]=u,w=(w-f[u]+mod)%mod,u=v;
if(is[v].ids>=1 and is[v].g[0][1]==w) v=is[v].g[0][0];
else v=is[v].g[1][0];
}
ll len=0; u=0;
for(ll i=n;i>=1;i--){
if(vis[i]) continue;
C.query(val[i],i);
ld[i]=ld[pre[i]]+1;len=max(len,ld[i]);
C.update(val[i],i);
}
if(len!=lds) puts("-1"),exit(0);
for(ll i=1;i<=n;i++){
if(vis[i]) continue;
if(ld[i]==lds){ u=i; break; }
}
printf("%lld\n",lis); for(ll i=1;i<=lis;i++) printf("%lld ",ans[i]);
printf("\n%lld\n",lds); for(ll i=1;i<=lds;i++) printf("%lld ",u),u=pre[u];
puts(""),exit(0);
}

浙公网安备 33010602011771号