2019/3/21模拟赛(构造,分治FFT,树套树)
\(T1\)
解题思路
硬核构造题,根据样例的提示。目前的思路就是让后手拿到\(K\),先手继续拿\(K-1\),后手继续拿\(K-2\),以此类推。那么可以这样构造:
3 1 K-3 K-4 .. ..
2 4 K-2 .. .. ..
5 K K-1 .. .. Z
Z-1 Z-2 ..
那么这样的话先手刚开始会拿\(3\)后手拿\(2\),先手拿\(5\),后手拿\(K\),这样就到了上面的局面。\(n<=3\)需要特判一下。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=1005;
int n,m,ans[N][N],xx[N*N],yy[N*N];
int main(){
scanf("%d%d",&n,&m);
int K=n*m;
if(n==1){
printf("3 2 1 ");
for(int i=m;i>3;i--)
printf("%d ",i);
putchar('\n');
for(int i=1;i<=m;i++)
printf("1 %d\n",i);
return 0;
}
if(n==2){
ans[1][1]=3;
ans[2][1]=2;
ans[1][2]=1;
ans[2][2]=K;
K--;
for(int i=1;i<=m-2;i++){
if(i&1){
for(int j=2;j;j--)
ans[j][i+2]=K,xx[K]=j,yy[K]=i+2,K--;
}
else {
for(int j=1;j<=2;j++)
ans[j][i+2]=K,xx[K]=j,yy[K]=i+2,K--;
}
}
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++)
printf("%d ",ans[i][j]);
putchar('\n');
}
printf("1 1\n2 1\n2 2\n");
for(int i=n*m-1;i>3;i--)
printf("%d %d\n",xx[i],yy[i]);
printf("1 2\n");
return 0;
}
if(n==3 && m==3) {
printf("6 1 3\n9 5 2\n8 7 4\n1 3\n2 3\n3 3\n3 2\n3 1\n2 1\n1 1\n2 2\n1 2\n");
return 0;
}
if(n==3 && m==4){
printf("3 2 4 7\n1 6 11 8\n5 10 12 9\n");
printf("1 1\n1 2\n2 1\n2 2\n2 3\n3 3\n3 2\n3 4\n2 4\n1 4\n3 1\n1 3\n");
return 0;
}
ans[1][1]=3; ans[1][2]=1; ans[2][1]=2;
ans[2][2]=4; ans[3][1]=5; ans[3][2]=K;
ans[1][3]=K-3; ans[2][3]=K-2; ans[3][3]=K-1;
K-=4;
for(int i=1;i<=m-3;i++){
if(i&1) {
for(int j=1;j<=3;j++)
ans[j][i+3]=K,xx[K]=j,yy[K]=i+3,K--;
}
else {
for(int j=3;j;j--)
ans[j][i+3]=K,xx[K]=j,yy[K]=i+3,K--;
}
}
for(int i=1;i<=n-3;i++){
if(i&1) {
for(int j=1;j<=m;j++)
ans[i+3][j]=K,xx[K]=i+3,yy[K]=j,K--;
}
else {
for(int j=m;j;j--)
ans[i+3][j]=K,xx[K]=i+3,yy[K]=j,K--;
}
}
// cerr<<K<<endl;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
printf("%d ",ans[i][j]);
putchar('\n');
}
printf("1 1\n2 1\n3 1\n3 2\n3 3\n2 3\n1 3\n");
for(int i=n*m-4;i>5;i--)
printf("%d %d\n",xx[i],yy[i]);
printf("2 2\n1 2\n");
return 0;
}
T3
解题思路
考场上犯了一个愚蠢到极点的有关宏定义的错误,导致炸成20。。这道题其实就是\(LUOGU4891\)。直接区间线段树套权值线段树即可,时空复杂度\(O(nlog^2n)\),需要离散化和垃圾回收卡空间。
代码
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast","inline")
#include<bits/stdc++.h>
#define mid ((l+r)>>1)
using namespace std;
const int N=100001;
const int M=N*350;
const int MOD=1e9+7;
inline int rd(){
int x=0,f=1; char ch=getchar();
while(!isdigit(ch)) f=ch=='-'?0:1,ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return f?x:-x;
}
int n,Q,a[N],b[N],c[N],rt[270005],ans;
int bin[N*150],cur,cpy[N*3],num,u;
int fast_pow(int x,int y){
int ret=1;
for(;y;y>>=1){
if(y&1) ret=1ll*ret*x%MOD;
x=1ll*x*x%MOD;
}
return ret;
}
struct Ask{
int op,x,y;
Ask(int _op=0,int _x=0,int _y=0){
op=_op; x=_x; y=_y;
}
}ask[N];
struct Seg1{
int ls[M],rs[M],tot,Mul[M],num[M];
int newnode(){
if(!cur) return ++tot;
return bin[cur--];
}
void init(){
for(int i=0;i<=M-5;i++)
Mul[i]=1;
}
void update(int &x,int l,int r,int pos,int tp){
if(!x) x=++tot;
if(l==r) {
if(tp){
Mul[x]=1ll*Mul[x]*cpy[pos]%MOD;
num[x]++;
}
else {
Mul[x]=1ll*Mul[x]*fast_pow(cpy[pos],MOD-2)%MOD;
num[x]--;
if(!num[x]) bin[++cur]=x,x=0;
}
return;
}
if(pos<=mid) update(ls[x],l,mid,pos,tp);
else update(rs[x],mid+1,r,pos,tp);
Mul[x]=1ll*Mul[ls[x]]*Mul[rs[x]]%MOD;
num[x]=num[ls[x]]+num[rs[x]];
if(!num[x]) bin[++cur]=x,x=0;
}
int query(int x,int l,int r,int L,int R){
if(Mul[x]==1) return 1;
if(!x) return 1;
if(L<=l && r<=R) return Mul[x];
int ret=1;
if(L<=mid) ret=1ll*ret*query(ls[x],l,mid,L,R)%MOD;
if(mid<R) ret=1ll*ret*query(rs[x],mid+1,r,L,R)%MOD;
return ret;
}
int query_num(int x,int l,int r,int L,int R){
if(!x) return 0;
if(!num[x]) return 0;
if(L<=l && r<=R) return num[x];
int ret=0;
if(L<=mid) ret+=query_num(ls[x],l,mid,L,R);
if(mid<R) ret+=query_num(rs[x],mid+1,r,L,R);
return ret;
}
}t1;
struct Seg2{
void build(int x,int l,int r){
for(int i=l;i<=r;i++) t1.update(rt[x],1,u,b[i],1);
if(l==r) return;
build(x<<1,l,mid); build(x<<1|1,mid+1,r);
}
void update(int x,int l,int r,int pos,int k,int tp){
t1.update(rt[x],1,u,k,tp);
if(l==r) return;
if(pos<=mid) update(x<<1,l,mid,pos,k,tp);
else update(x<<1|1,mid+1,r,pos,k,tp);
}
int query(int x,int l,int r,int L,int R,int ll,int rr){
if(L<=l && r<=R) return t1.query(rt[x],1,u,ll,rr);
int ret=1;
if(L<=mid) ret=1ll*ret*query(x<<1,l,mid,L,R,ll,rr)%MOD;
if(mid<R) ret=1ll*ret*query(x<<1|1,mid+1,r,L,R,ll,rr)%MOD;
return ret;
}
int query_num(int x,int l,int r,int L,int R,int ll,int rr){
if(L<=l && r<=R) return t1.query_num(rt[x],1,u,ll,rr);
int ret=0;
if(L<=mid) ret+=query_num(x<<1,l,mid,L,R,ll,rr);
if(mid<R) ret+=query_num(x<<1|1,mid+1,r,L,R,ll,rr);
return ret;
}
}t2;
struct Seg3{
int Max[270005],tag[270005];
void pushdown(int x){
Max[x<<1]=max(Max[x<<1],tag[x]);
Max[x<<1|1]=max(Max[x<<1|1],tag[x]);
tag[x<<1]=max(tag[x],tag[x<<1]);
tag[x<<1|1]=max(tag[x],tag[x<<1|1]);
tag[x]=0;
}
void build(int x,int l,int r){
if(l==r) {Max[x]=c[l]; return;}
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
Max[x]=max(Max[x<<1],Max[x<<1|1]);
}
void update(int x,int l,int r,int L,int R,int k){
if(L<=l && r<=R) {
Max[x]=max(Max[x],k);
tag[x]=max(tag[x],k);
return;
}
if(tag[x]) pushdown(x);
if(L<=mid) update(x<<1,l,mid,L,R,k);
if(mid<R) update(x<<1|1,mid+1,r,L,R,k);
Max[x]=max(Max[x<<1],Max[x<<1|1]);
}
int query(int x,int l,int r,int pos){
if(l==r) return Max[x];
if(tag[x]) pushdown(x);
if(pos<=mid) return query(x<<1,l,mid,pos);
return query(x<<1|1,mid+1,r,pos);
}
}t3;
int Div(int l,int r,int w){
int ret;
while(l<=r){
if((t3.query(1,1,n,mid))==w) ret=mid,l=mid+1;
else r=mid-1;
}
return ret;
}
int main(){
n=rd(); Q=rd(); t1.init(); int op,x,y;
for(int i=1;i<=n;i++) a[i]=rd(),cpy[++num]=a[i];
for(int i=1;i<=n;i++) b[i]=rd(),cpy[++num]=b[i];
//lsh
for(int i=1;i<=Q;i++){
op=rd(),x=rd(),y=rd();
ask[i]=Ask(op,x,y);
cpy[++num]=y;
}
sort(cpy+1,cpy+1+num);
u=unique(cpy+1,cpy+1+num)-cpy-1;
for(int i=1;i<=n;i++)
b[i]=lower_bound(cpy+1,cpy+1+u,b[i])-cpy;
for(int i=1;i<=n;i++)
a[i]=lower_bound(cpy+1,cpy+1+u,a[i])-cpy;
for(int i=1;i<=Q;i++)
ask[i].y=lower_bound(cpy+1,cpy+1+u,ask[i].y)-cpy;
for(int i=1;i<=n;i++) c[i]=max(a[i],c[i-1]);
ans=1;
// for(int i=1;i<=n;i++) cout<<c[i]<<" ";cout<<endl;
for(int i=1;i<=n;i++) ans=1ll*ans*min(cpy[c[i]],cpy[b[i]])%MOD;
t2.build(1,1,n); t3.build(1,1,n);
// cerr<<t3.query(1,1,n,2)<<endl;
// cerr<<t2.query_num(1,1,n,1,n,1,5)<<endl;
// cerr<<ans<<endl;
for(int i=1;i<=Q;i++){
op=ask[i].op,x=ask[i].x,y=ask[i].y;
if(op==1){
t2.update(1,1,n,x,b[x],0);
t2.update(1,1,n,x,y,1);
int tmp=t3.query(1,1,n,x);
if(tmp>b[x]) ans=1ll*ans*fast_pow(cpy[b[x]],MOD-2)%MOD;
else ans=1ll*ans*fast_pow(cpy[tmp],MOD-2)%MOD;
b[x]=y;
if(tmp>b[x]) ans=1ll*ans*cpy[b[x]]%MOD;
else ans=1ll*ans*cpy[tmp]%MOD;
}
else {
int now=x,tmp,R,NUM,sum;
while(now<=n){
tmp=t3.query(1,1,n,now);
// cerr<<tmp<<endl;
if(tmp>=y) break;
// cerr<<tmp<<endl;
R=Div(now,n,tmp);
// if(x==1) cout<<R<<endl;
// cerr<<R<<endl;
// if(x==2) cout<<tmp<<" "<<R<<endl;
NUM=t2.query_num(1,1,n,now,R,tmp,y);
int NUM2=t2.query_num(1,1,n,now,R,y+1,u);
ans=1ll*ans*fast_pow(cpy[y],NUM2)%MOD;
sum=t2.query(1,1,n,now,R,tmp,y);
ans=1ll*ans*sum%MOD;
ans=1ll*ans*fast_pow(fast_pow(cpy[tmp],MOD-2),NUM2+NUM)%MOD;
now=R+1;
}
// cerr<<t3.query(1,1,n,4)<<endl;
t3.update(1,1,n,x,n,y);
}
printf("%d\n",ans);
}
return 0;
}