联合省选 2021

卡牌游戏(card)

俩数组放在一起拍个序然后双指针扫一下即可。

代码懒得写了。

矩阵游戏(matrix)

Link

考虑没有「其每个元素为大小不超过 \({10}^6\) 的非负整数」这个限制怎么做,显然令 \(a_{i,1}=a_{1,j}\;(1\le i\le n,\;1\le j\le m)\) 然后一个一个算其余的 \(a_{i,j}\) 即可。

\[\left[\begin{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}\right] \]

我们得到了一个弱化版的答案,现在加上这个条件。考虑这个矩阵的第 \(i\) 行,若 \(j\) 为奇数加一个 \(r_i\),反之减一个 \(r_i\),列类似:

\[\left[\begin{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}\right] \]

这样表示仍然是满足题意的。非常像差分约束,但是加法我们不会做,于是定义:

\[r_i'=\begin{cases}r_i, &i\equiv 1\pmod 2\\ -r_i & i\equiv 0\pmod 2\end{cases}\\ c_i'=\begin{cases}c_i, &i\equiv 0\pmod 2\\ -c_i & i\equiv 1\pmod 2\end{cases} \]

原矩阵变成了:

\[\left[\begin{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}\right] \]

就可以差分约束了。

显然每行/每列加减同一个数肯定能构造出有解的矩阵,因为如果有解,第一行、第一列对应的数一定是解中的数。

#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;
}

宝石(gem)

\(u\sim v\) 的路径拆成 \(u\sim \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\n",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\n",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\n",ans1);
    else printf("%d\n",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;
}

滚榜(ranklist)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef vector<int> vi;
#define mp make_pair
#define pb push_back
#define fi first
#define se second
inline int read()
{
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    return x*f;
}
void write(int n)
{
    if(n<0)putchar('-'),n=-n;
    if(n>9)write(n/10);
    putchar(n%10^48);
}
int a[20],dt[20][20];//dt[i][j]:上一个是i,下一个是j
ll f[1<<13][14][510];
int pop[1<<13],s[20];
int main()
{
    int n=read(),m=read();
    for(int i=1;i<(1<<13);i++)pop[i]=pop[i>>1]+(i&1);
    for(int i=1;i<=n;i++)a[i]=read();
    for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(i!=j)dt[i][j]=max(0,a[i]-a[j]+(i<j)),s[j]=max(s[j],dt[i][j]);
    for(int i=1;i<=n;i++)if(s[i]*n<=m)f[1<<(i-1)][i][s[i]*n]=1;
    for(int s=1;s<(1<<n);s++)
    {
        for(int i=1;i<=n;i++)
        {
            if(!(s&(1<<(i-1))))continue;
            for(int j=0;j<=m;j++)
            {
                if(!f[s][i][j])continue;
                for(int t=1;t<=n;t++)
                {
                    if(s&(1<<(t-1)))continue;
                    if(j+(n-pop[s|(1<<(t-1))]+1)*dt[i][t]<=m)
                        f[s|(1<<(t-1))][t][j+(n-pop[s|(1<<(t-1))]+1)*dt[i][t]]+=f[s][i][j];
                }
            }
        }
    }
    ll ans=0;
    for(int i=1;i<=n;i++)for(int j=0;j<=m;j++)ans+=f[(1<<n)-1][i][j];
    printf("%lld",ans);
    return 0;
}
//zzt qwq
posted @ 2021-05-12 20:14  zzt1208  阅读(81)  评论(1编辑  收藏  举报