4.6省选模拟

我太菜了

\(T1\)意识到应该分开处理,但是确实没有想到使用矩阵转移,然后试图暴力推式子无果,就打了打暴力

\(T2\)确实这分治\(+\)最短路太强了....试图在建图上寻找突破点无果,这种题确实是第一次见到,并没有想出来

\(T3\)提答,手玩前两组,感觉高维需要处理一堆东西

这一场打的很差,还是见的少了

\(T1\)

考虑我们要分别输出分子分母,那么必然需要单独维护

计算\(x+\frac{z}{y}=\frac{xy+z}{y}\)

较为显然,\(gcd(xy+z,y)=gcd(y,z)=1,\)那么这个永远不会被约分

那么也就是说,我们上下不需要进行\(gcd\)运算,直接上下单独维护,互相转移就好了

大概明白了

我们现在拥有了当前状态的分子分母,假设新加一个数字

\(\huge\frac{1}{a_0+\frac{1}{a_1+\frac{1}{a+2+...}}}\)

我们现在是\(\frac{a}{b},\)那么新加一个数字\(a_i\)

\(\huge \frac{1}{a_i+\frac{a}{b}}=\frac{1}{\frac{a_ib+a}{b}}=\frac{b}{a_ib+a}\)

那么可以显然的得到转移矩阵(当然我们最后是从右边乘到左边,我们为了从左到右转移,把转移矩阵放到左边就可以区间整体转移了)

那么转移矩阵易得

\(\begin{bmatrix} 0 & 1 \\ 1 & a_i \end{bmatrix}\times\begin{bmatrix} a \\ b \end{bmatrix}=\begin{bmatrix} b \\ a_ib+a \end{bmatrix} \quad\)

那么直接这样直接变转移边取模是没有问题的,反正分子分母的转移形式已经确定并且不会约分,那么直接取模是没有问题的

那么整体转移式子大概就是这个样子,考虑维护出这样一个转移序列就好了

\(\begin{bmatrix} 0 & 1 \\ 1 & a_1 \end{bmatrix}...\begin{bmatrix} 0 & 1 \\ 1 & a_n \end{bmatrix}\times\begin{bmatrix} 1 \\ 0 \end{bmatrix}\)

那么这道题的操作也比较显然需要用矩阵表示一下

那么对于\(W\)操作,\(a_k->a_k+1\)

那么考虑一下我们最后的那个矩阵的变化

\(\begin{bmatrix} 0 & 1 \\ 1 & a_k \end{bmatrix}->\begin{bmatrix} 0 & 1 \\ 1 & a_k+1 \end{bmatrix}\)

那么,构造\(+1\)矩阵

\(\begin{bmatrix} 0 & 1 \\ 1 & a_k \end{bmatrix}\times \begin{bmatrix} 1 & 1 \\ 0 & 1 \end{bmatrix}=\begin{bmatrix} 0 & 1 \\ 1 & a_k+1 \end{bmatrix}\)

对于\(E\)操作

我们有两种情况,\(a_k>1,a_k<=1\)

\(Sit_1:(a_k>1)\)

\(\begin{bmatrix} 0 & 1 \\ 1 & a_k \end{bmatrix}\times \begin{bmatrix} 1 & -1 \\ 0 & 1 \end{bmatrix}=\begin{bmatrix} 0 & 1 \\ 1 & a_k-1 \end{bmatrix}\)

又增加两个,那么相当于在末尾增加两个矩阵

\(\begin{bmatrix} 0 & 1 \\ 1 & 1 \end{bmatrix}\begin{bmatrix} 0 & 1 \\ 1 & 1 \end{bmatrix}\)

那么总的可以把三个矩阵乘起来

\(\begin{bmatrix} 1 & -1 \\ 0 & 1 \end{bmatrix}\begin{bmatrix} 0 & 1 \\ 1 & 1 \end{bmatrix}\begin{bmatrix} 0 & 1 \\ 1 & 1 \end{bmatrix}=\begin{bmatrix} 0 & -1 \\ 1 & 2 \end{bmatrix}\)

\(Sit_2:(a_k<=1)\)

对于\(a_{k-1}->a_{k-1}+1\)

考虑最后两个矩阵\(k-1,k\)

\(\begin{bmatrix} 0 & 1 \\ 1 & a_{k-1} \end{bmatrix}\begin{bmatrix} 0 & 1 \\ 1 & 1 \end{bmatrix}\)

那么最后应该变化为

\(\begin{bmatrix} 0 & 1 \\ 1 & a_{k-1} \end{bmatrix}\begin{bmatrix} 1 & 1 \\ 0 & 1 \end{bmatrix}\begin{bmatrix} 0 & 1 \\ 1 & 1 \end{bmatrix}\)

由于矩阵乘法有结合律,可以先把后两项乘起来

\(\begin{bmatrix} 0 & 1 \\ 1 & a_{k-1} \end{bmatrix}\begin{bmatrix} 1 & 2 \\ 1 & 1 \end{bmatrix}\)

考虑能否直接在原序列最后直接乘上\(Sit_1\)的转移矩阵得到同样效果

\(\begin{bmatrix} 0 & 1 \\ 1 & a_{k-1} \end{bmatrix}\begin{bmatrix} 0 & 1 \\ 1 & 1 \end{bmatrix}\begin{bmatrix} 0 & -1 \\ 1 & 2 \end{bmatrix}=\begin{bmatrix} 0 & 1 \\ 1 & a_{k=1} \end{bmatrix}\begin{bmatrix} 1 & 2 \\ 1 & 1 \end{bmatrix}\)

目前我们知道了所有的转移矩阵,那么就需要维护翻转.取反,区间乘积的数据结构,那我们祭出平衡树即可

那么就是痛苦的手搓平衡树环节了

#include<bits/stdc++.h>
#define int long long
#define mod 998244353
#define ls son[now][0]
#define rs son[now][1]
#define MAXN 200005
using namespace std;
mt19937 rnd(20050323);
int n,q,son[MAXN][2],siz[MAXN],val[MAXN],rev[MAXN],qf[MAXN];
int sta[MAXN],top;
struct Mat{
	int jz[2][2];
	void Init() 
	{
		 memset(jz,0,sizeof(jz));
    }
	Mat operator *(const Mat &a)
	{
		Mat res;
		res.Init();
		for(int i=0;i<2;i++)
		{
			for(int j=0;j<2;j++)
			{
				for(int k=0;k<2;k++)
				{
					(res.jz[i][j]+=(jz[i][k]*a.jz[k][j])%mod)%=mod;
				}
			}
		}
		return res;
	}
}f[4][MAXN],zy[2];
void tupt(int now,int t)
{
	f[t][now]=f[t][ls]*zy[sta[now]]*f[t][rs];
}
void swp(int now,int a,int b)
{
	 swap(f[a][now],f[b][now]);
}
void pushdown(int now)
{
	if(rev[now])
	{
		swap(ls,rs);
		swp(now,0,1),swp(now,2,3);
		rev[ls]^=1, 
		rev[rs]^=1;
		rev[now]=0;
	}
	if(qf[now])
	{
		sta[now]^=1;
		swp(now,0,2),swp(now,1,3);
		qf[ls]^=1;
		qf[rs]^=1;
		qf[now]=0;
	}
}
void upt(int now)
{
	pushdown(ls);
	pushdown(rs);
	siz[now]=siz[ls]+siz[rs]+1;
	tupt(now,0);
	swap(ls,rs);
	tupt(now,1);
	swap(ls,rs);
	sta[now]^=1;
	tupt(now,2);
	swap(ls,rs);
	tupt(now,3);
	swap(ls,rs);
	sta[now]^=1;
}
int newnode(int t)
{
	sta[++top]=t;
	upt(top);
	val[top]=rnd();
	return top;
}
int merge(int x, int y)
{
	if(!x||!y) return x|y;
	pushdown(x);
	pushdown(y);
	int now;
	if(val[x]>val[y])
	{
		now=x;
		rs=merge(rs,y);
	}
	else
	{
		now=y;
		ls=merge(x,ls);
	}
	upt(now);
	return now;
}
void split(int now,int &x,int &y,int k)
{
	if(!now) 
	{
	   x=y=0; 
	   return; 
	}
	pushdown(now);
	if(k>=siz[ls]+1)
	{
		x=now;
		split(rs,rs,y,k-siz[ls]-1);
	}
	else
	{
		y=now;
		split(ls,x,ls,k);
	}
	upt(now);
}
int rt;
void append(int t)
{
	rt=merge(rt,newnode(t));
}
void flip(int l,int r)
{
	int x,y,z;
	split(rt,y,z,r);
	split(y,x,y,l-1);
	qf[y]^=1;
	rt=merge(x,y);
	rt=merge(rt,z);
}
void reve(int l,int r)
{
	int x,y,z;
	split(rt,y,z,r);
	split(y,x,y,l-1);
	rev[y]^=1;
	rt=merge(x,y);
	rt=merge(rt,z);
}
void ask()
{
	pushdown(rt);
	int a=f[0][rt].jz[0][0],b=f[0][rt].jz[1][0];
	printf("%lld %lld\n",a,(a+b)%mod);
}
char s[MAXN];
signed main()
{
	scanf("%lld%lld",&n,&q);
	zy[0].jz[0][0]=zy[0].jz[1][0]=zy[0].jz[1][1]=1;
	zy[1].jz[0][0]=2,zy[1].jz[0][1]=1,zy[1].jz[1][0]=mod-1;
	scanf("%s",s+1);
	for(int i=0;i<4;i++) f[i][0].jz[0][0]=f[i][0].jz[1][1]=1;
	for(int i=1;i<=n;i++) append(s[i]=='E');
	ask();
	for(int i=1,l,r;i<=q;i++)
	{
		scanf("%s",s);
		if(s[0]=='A')
		{
			scanf("%s",s);
			append(s[0]=='E');
		}
		else scanf("%lld%lld",&l,&r);
		if(s[0]=='F') flip(l,r);
		else if(s[0]=='R') reve(l, r);
		ask();
	}
	return 0;
}

\(T2\)

确实没有想到,需要把询问离线然后分治时候跑最短路

对于原矩阵进行分割,分割成两个矩阵,然后对于所有的点求一下最短路,然后以直线上的点为必经点更新询问

#include<bits/stdc++.h>
#define INF 2147483647
#define MAXN 100010
#define MAXM 50010
using namespace std;
int n,m,q,ans[MAXN];
template<typename Tp>
void read(Tp &x)
{
	x=0;int f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}x*=f;
}
struct Que
{
	int id;
	int x,y,xx,yy,p1,p2;
}p[MAXN],tmp1[MAXN],tmp2[MAXN],tmp3[MAXN];

priority_queue<pair<int,int> > pq;
int dis[MAXM],hah[MAXM];
int tot,to[MAXM<<1],nxt[MAXM<<1],head[MAXM],val[MAXM<<1];
int id(int x,int y)
{
    return (x-1)*m+y; 
}
void add(int u,int v,int w)
{
	tot++;
	to[tot]=v;
	val[tot]=w;
	nxt[tot]=head[u];
	head[u]=tot;
}
void dij(int l1,int r1,int l2,int r2,int x)
{
	for(int i=l1;i<=r1;i++)
	{
		for(int j=l2;j<=r2;j++)
		{
			int pos=id(i,j);
			dis[pos]=INF;
			hah[pos]=0;
		}
	}
	dis[x]=0;
	pq.push(make_pair(0,x));
	while(!pq.empty())
	{
		int x=pq.top().second;
		pq.pop();
		if(hah[x]) continue;
		hah[x]=1;
		for(int i=head[x];i;i=nxt[i])
		{
			int y=to[i];
			int xx=(y/m)+(y%m!=0),yy=(y%m==0)?m:y%m;
			if(xx<l1||xx>r1||yy<l2||yy>r2) continue;
			if(dis[x]+val[i]<dis[y]) 
			{
				dis[y]=dis[x]+val[i];
				pq.push(make_pair(-dis[y],y));
			}
		}
	}
}
 
void sol(int l1,int r1,int l2,int r2,int L,int R)
{
	if(l1>r1||l2>r2||L>R) return;
	int len1=r1-l1+1,len2=r2-l2+1;
	if(len1<len2)
	{
		int mid=(l2+r2)>>1;
		for(int i=l1;i<=r1;i++)
		{
			int pos=id(i,mid);	
			dij(l1,r1,l2,r2,pos);
			for(int j=L;j<=R;j++) ans[p[j].id]=min(ans[p[j].id],dis[p[j].p1]+dis[p[j].p2]);
		}	
		int k1=0,k2=0,k3=0,cnt=L-1;
		for(int i=L;i<=R;i++)
		{
			if(p[i].y<mid&&p[i].yy<mid) tmp1[++k1]=p[i];
			else if(p[i].y>mid&&p[i].yy>mid) tmp2[++k2]=p[i];
			else tmp3[++k3]=p[i];
		}
		for(int i=1;i<=k1;i++) p[++cnt]=tmp1[i];
		for(int i=1;i<=k3;i++) p[++cnt]=tmp3[i];
		for(int i=1;i<=k2;i++) p[++cnt]=tmp2[i];
		sol(l1,r1,l2,mid-1,L,L+k1-1);
		sol(l1,r1,mid+1,r2,R-k2+1,R);
	}
	else
	{
		int mid=(l1+r1)>>1;
		for(int i=l2;i<=r2;i++)
		{
			int pos=id(mid,i);
			dij(l1,r1,l2,r2,pos);
			for(int j=L;j<=R;j++) ans[p[j].id]=min(ans[p[j].id],dis[p[j].p1]+dis[p[j].p2]);
		}	
		int k1=0,k2=0,k3=0,cnt=L-1;
		for(int i=L;i<=R;i++)
		{
			if(p[i].x<mid&&p[i].xx<mid) tmp1[++k1]=p[i];
			else if(p[i].x>mid&&p[i].xx>mid) tmp2[++k2]=p[i];
			else tmp3[++k3]=p[i];
		}
		for(int i=1;i<=k1;i++) p[++cnt]=tmp1[i];
		for(int i=1;i<=k3;i++) p[++cnt]=tmp3[i];
		for(int i=1;i<=k2;i++) p[++cnt]=tmp2[i];
		sol(l1,mid-1,l2,r2,L,L+k1-1);
		sol(mid+1,r1,l2,r2,R-k2+1,R);
	}
}

int main()
{
	read(n),read(m);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<m;j++)
		{
			int u=id(i,j),v=id(i,j+1),w;
			read(w);
			add(v,u,w),add(u,v,w);
		}
	}
	for(int i=1;i<n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			int u=id(i,j),v=id(i+1,j),w;
			read(w);
			add(u,v,w),add(v,u,w);
		}
	}
	read(q);
	for(int i=1;i<=q;i++)
	{
		read(p[i].x),read(p[i].y),read(p[i].xx),read(p[i].yy);
		p[i].p1=id(p[i].x,p[i].y),p[i].p2=id(p[i].xx,p[i].yy);
		p[i].id=i,ans[i]=INF;
	}
	sol(1,n,1,m,1,q);
	for(int i=1;i<=q;i++) printf("%d\n",ans[i]);
	return 0;
}

\(T3\)

神仙题(作为一个三维的屑属实想不出来高维怎么整)

怎么表示\(n\)维度一个面

二维,面既是线,\(a_1x_1+a_2x_2=b\)

三维,面就是面(废话),\(a_1x_1+a_2x_2+a_3x_3=d\)

拓展到高维公式一致

对于第\(i\)个球,\(|\sum_j a_jx_{i,j}-d|=r\)

枚举正负号高斯消元即可

posted @ 2022-04-06 17:39  Authentic_k  阅读(20)  评论(0编辑  收藏  举报