卡牌游戏
俩数组放在一起拍个序然后双指针扫一下即可。
代码懒得写了。
矩阵游戏
考虑没有「其每个元素为大小不超过 ({10}^6) 的非负整数」这个限制怎么做,显然令 (a_{i,1}=a_{1,j};(1le ile n,;1le jle m)) 然后一个一个算其余的 (a_{i,j}) 即可。
[left[egin{matrix}a_{1,1} & a_{1,2} & a_{1,3} & a_{1,4}\ a_{2,1} & a_{2,2} & a_{2,3} & a_{2,4}\ a_{3,1} & a_{3,2} & a_{3,3} & a_{3,4}\ a_{4,1} & a_{4,2} & a_{4,3} & a_{4,4}end{matrix}
ight]
]
我们得到了一个弱化版的答案,现在加上这个条件。考虑这个矩阵的第 (i) 行,若 (j) 为奇数加一个 (r_i),反之减一个 (r_i),列类似:
[left[egin{matrix}a_{1,1}+r_1+c_1 & a_{1,2}-r_1+c_2 & a_{1,3}+r_1+c_3 & a_{1,4}-r_1+c_4\ a_{2,1}+r_2-c_1 & a_{2,2}-r_2-c_2 & a_{2,3}+r_2-c_3 & a_{2,4}-r_2-c_4\ a_{3,1}+r_3+c_1 & a_{3,2}-r_3+c_2 & a_{3,3}+r_3+c_3 & a_{3,4}-r_3+c_4\ a_{4,1}+r_4-c_1 & a_{4,2}-r_4-c_2 & a_{4,3}+r_4-c_3 & a_{4,4}-r_4-c_4end{matrix}
ight]
]
这样表示仍然是满足题意的。非常像差分约束,但是加法我们不会做,于是定义:
[r_i'=egin{cases}r_i, &iequiv 1pmod 2\ -r_i & iequiv 0pmod 2end{cases}\
c_i'=egin{cases}c_i, &iequiv 0pmod 2\ -c_i & iequiv 1pmod 2end{cases}
]
原矩阵变成了:
[left[egin{matrix}a_{1,1}+r_1'-c_1' & a_{1,2}-r_1'+c_2' & a_{1,3}+r_1'-c_3' & a_{1,4}-r_1'+c_4'\ a_{2,1}-r_2'+c_1' & a_{2,2}+r_2'-c_2' & a_{2,3}-r_2'+c_3' & a_{2,4}+r_2'-c_4'\ a_{3,1}+r_3'-c_1' & a_{3,2}-r_3'+c_2' & a_{3,3}+r_3'-c_3' & a_{3,4}-r_3'+c_4'\ a_{4,1}-r_4'+c_1' & a_{4,2}+r_4'-c_2' & a_{4,3}-r_4'+c_3' & a_{4,4}+r_4'-c_4'end{matrix}
ight]
]
就可以差分约束了。
显然每行/每列加减同一个数肯定能构造出有解的矩阵,因为如果有解,第一行、第一列对应的数一定是解中的数。
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e6+10,M=2e6+10;
int head[N],ver[M],nxt[M],tot=0,edge[M];
void add(int x,int y,int z)
{
ver[++tot]=y;
edge[tot]=z;
nxt[tot]=head[x];
head[x]=tot;
}
int dis[N],cnt[N];int n,m;
bool vis[N],book[N];
bool spfa(int S)
{
queue<int> que;
dis[S]=0;
que.push(S);
while(!que.empty())
{
int x=que.front();que.pop();
book[x]=1;
vis[x]=0;
for(int i=head[x];i;i=nxt[i])
{
int y=ver[i],z=edge[i];
if(dis[x]+z>dis[y])
{
dis[y]=dis[x]+z;
if(++cnt[y]>n+m)return true;
if(!vis[y])
{
vis[y]=1;
que.push(y);
}
}
}
}
return false;
}
int a[310][310],b[310][310];
void sol()
{
memset(vis,0,sizeof(vis));
memset(dis,-0x3f,sizeof(dis));
memset(book,0,sizeof(book));
memset(cnt,0,sizeof(cnt));
memset(a,0,sizeof(a));
scanf("%lld%lld",&n,&m);
for(int i=1;i<n;i++)for(int j=1;j<m;j++)scanf("%lld",&b[i][j]);
for(int i=2;i<=n;i++)for(int j=2;j<=m;j++)a[i][j]=b[i-1][j-1]-a[i][j-1]-a[i-1][j]-a[i-1][j-1];
memset(head,0,sizeof(head));tot=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if((i+j)&1)add(i,j+n,-a[i][j]),add(j+n,i,a[i][j]-1e6);
else add(j+n,i,-a[i][j]),add(i,j+n,a[i][j]-1e6);
}
}
if(spfa(1)){puts("NO");return;}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if((i+j)&1)a[i][j]+=-dis[i]+dis[j+n];
else a[i][j]+=dis[i]-dis[j+n];
}
}
puts("YES");
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)printf("%lld ",a[i][j]);
puts("");
}
}
signed main()
{
// freopen("matrix5.in","r",stdin);
int T;
scanf("%lld",&T);
while(T--) sol();
return 0;
}
宝石
将 (usim v) 的路径拆成 (usim operatorname{lca}(u,v))(含 (operatorname{lca}))和 (operatorname{lca}(u,v)sim v)(不含)。将 (w) 重新标号后第一段路径直接倍增即可,第二段路径二分之后再倍增即可。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
inline int read()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='0')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return x*f;
}
const int N=2e5+10,M=4e5+10;
int head[N],ver[M],nxt[M],tot=0;
void add(int x,int y)
{
ver[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
}
int pos[N],p[N],w[N];
int n,m,c,t,rt[N];
struct president_tree
{
int tot;
struct node
{
int lc,rc,val;
node(){lc=rc=val=0;}
}t[N<<5];
president_tree(){tot=0;}
int build(int l,int r)
{
int p=++tot,mid=(l+r)/2;
if(l==r) return p;
t[p].lc=build(l,mid);
t[p].rc=build(mid+1,r);
return p;
}
int modify(int pre,int l,int r,int x,int d)
{
int p=++tot,mid=(l+r)/2;
t[p]=t[pre];
if(l==r){t[p].val=d;return p;}
if(x<=mid)t[p].lc=modify(t[pre].lc,l,mid,x,d);
else t[p].rc=modify(t[pre].rc,mid+1,r,x,d);
return p;
}
int query(int p,int l,int r,int x)
{
if(l==r) return t[p].val;
int mid=(l+r)/2;
if(x<=mid)return query(t[p].lc,l,mid,x);
else return query(t[p].rc,mid+1,r,x);
}
}T;
int dep[N],fa[N][30];
void bfs(int s)
{
queue<int> que;
que.push(s);
dep[s]=1;
while(!que.empty())
{
int x=que.front();que.pop();
for(int i=head[x];i;i=nxt[i])
{
int y=ver[i];
if(dep[y])continue;
dep[y]=dep[x]+1;
fa[y][0]=x;
for(int j=1;j<=t;j++)fa[y][j]=fa[fa[y][j-1]][j-1];
que.push(y);
}
}
}
int lca(int x,int y)
{
if(dep[x]<dep[y])swap(x,y);
for(int i=t;i>=0;i--)if(dep[fa[x][i]]>=dep[y])x=fa[x][i];
if(x==y)return x;
for(int i=t;i>=0;i--)if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
int col[N],g1[N][30],g2[N][30];
void dfs1(int x)
{
int tmp=col[w[x]];
if(w[x])col[w[x]]=x;
if(w[x]!=c)g1[x][0]=col[w[x]+1];
for(int i=1;i<=t;i++)g1[x][i]=g1[g1[x][i-1]][i-1];
for(int i=head[x];i;i=nxt[i])
{
int y=ver[i];
if(y==fa[x][0])continue;
dfs1(y);
}
col[w[x]]=tmp;
}
void dfs2(int x)
{
int tmp=col[w[x]];
if(w[x])col[w[x]]=x;
if(w[x]&&w[x]!=1)g2[x][0]=col[w[x]-1];
for(int i=1;i<=t;i++)g2[x][i]=g2[g2[x][i-1]][i-1];
for(int i=head[x];i;i=nxt[i])
{
int y=ver[i];
if(y==fa[x][0])continue;
dfs2(y);
}
col[w[x]]=tmp;
}
void dfs(int x)
{
if(!w[x])rt[x]=rt[fa[x][0]];
else rt[x]=T.modify(rt[fa[x][0]],1,c,w[x],x);
for(int i=head[x];i;i=nxt[i])
{
int y=ver[i];
if(y==fa[x][0])continue;
dfs(y);
}
}
void Sol()
{
int u=read(),v=read(),L=lca(u,v);
u=T.query(rt[u],1,c,1);
int ans1=0;
if(dep[u]>=dep[L]) ans1=1;
for(int i=t;i>=0;i--)if(dep[g1[u][i]]>=dep[L])ans1+=(1<<i),u=g1[u][i];
if(ans1==c){printf("%d
",c);return;}
int l=ans1+1,r=c,ans2=0;
while(l<=r)
{
int mid=(l+r)/2;
int x=T.query(rt[v],1,c,mid);
// printf("v=%d, mid=%d, x=%d
",v,mid,x);
if(dep[x]<=dep[L]){r=mid-1;continue;}
for(int i=0;i<=t;i++)if((mid-ans1-1)&(1<<i))x=g2[x][i];
if(dep[x]>dep[L])l=mid+1,ans2=mid;
else r=mid-1;
}
if(!ans2)printf("%d
",ans1);
else printf("%d
",ans2);
}
int main()
{
n=read(),m=read(),c=read();
rt[0]=T.build(1,c);
t=(int)(log(n)/log(2))+1;
for(int i=1;i<=c;i++)pos[p[i]=read()]=i;
for(int i=1;i<=n;i++)w[i]=pos[read()];
for(int i=1;i<n;i++){int u=read(),v=read();add(u,v),add(v,u);}
bfs(1),dfs1(1),dfs2(1),dfs(1);
int q=read();
for(int i=1;i<=q;i++)Sol();
return 0;
}