[APIO2011]

来自FallDream的博客,未经允许,请勿转载,谢谢。

------------------------------------------------------

A.[Apio2011]方格染色

Sam和他的妹妹Sara有一个包含n × m个方格的表格。她们想要将其的每个方格都染成红色或蓝色。出于个人喜好,他们想要表格中每个2 ×   2的方形区域都包含奇数个(1 个或 3 个)红色方格。例如,右图是一个合法的表格染色方案(在打印稿中,深色代表蓝色,浅色代表红色) 。 可是昨天晚上,有人已经给表格中的一些方格染上了颜色!现在Sam和Sara非常生气。不过,他们想要知道是否可能给剩下的方格染上颜色,使得整个表格仍然满足她们的要求。如果可能的话,满足他们要求的染色方案数有多少呢?  $n,m,k\leqslant 10^{6}$

题解:打表观察了一波,除了答案貌似是2的倍数,很经常是$2^{n+m-1}$以外都不懂,无奈看题解。

我们可以把限制条件当作异或关系式,(我不懂怎么打异或,就用$\veebar$ 代替吧)即对于$x>1且y>1,S[x][y]\veebar S[x][y-1]\veebar S[x-1][y]\veebar S[x-1][y-1]=1$,对于一个在$(a,b),a>1,b>1$的已经有颜色的块,我们把所有$x\leqslant a,y\leqslant b$的异或关系式塔起来,得到$Sab\veebar S[a][1]\veebar S[1][b]\veebar S[1][1]=Color(a,b)$这个式子只有在ab都是偶数的时候,才等于1。假如确定了$(1,1)$的颜色,那我们就能用一个异或方程表示第a行和第b列的关系。那我们就直接枚举$(1,1)$的颜色,通过并查集维护就可以啦。在维护的时候,如果出现矛盾,说明无解,否则假设联通块有num个,答案是$2^{num-1}$

#include<iostream>
#include<cstdio>
#define MN 1000000
#define mod 1000000000
using namespace std;
inline int read()
{
    int x = 0 , f = 1; char ch = getchar();
    while(ch < ‘0‘ || ch > ‘9‘){ if(ch == ‘-‘) f = -1;  ch = getchar();}
    while(ch >= ‘0‘ && ch <= ‘9‘){x = x * 10 + ch - ‘0‘;ch = getchar();}
    return x * f;
}
int n,m,k,fa[MN*2+5],g[MN*2+5],ans=0;
struct limit{int x,y,z;}s[MN+5];

int pow(int x,int k)
{
    int sum=1;
    for(int i=x;k;k>>=1,i=1LL*i*i%mod)
        if(k&1)
            sum=1LL*sum*i%mod;
    return sum;
}

int getfa(int x)
{
    if(fa[x]==x) return x;
    int t=getfa(fa[x]);g[x]^=g[fa[x]];
    return fa[x]=t;
}

int calc()
{
    for(int i=1;i<=m+n;i++) fa[i]=i,g[i]=0;fa[n+1]=1;
    for(int i=1;i<=k;i++)
    {
        if(s[i].x+s[i].y<=2) continue;
        int x=getfa(s[i].x),y=getfa(s[i].y+n),t=g[s[i].x]^g[s[i].y+n]^s[i].z;
        if(x!=y){fa[x]=y;g[x]=t;}
        else if(t) return 0;
    }
    int num=0;
    for(int i=1;i<=n+m;i++)
        if(fa[i]==i) num++;
    return pow(2,num-1);
}

int main()
{
    n=read();m=read();k=read();
    bool flag[2];
    for(int i=1;i<=k;i++)
    {
        s[i].x=read();s[i].y=read();s[i].z=read();
        if(s[i].x+s[i].y<3) flag[s[i].z]=1;
        if(!(s[i].x&1||s[i].y&1)) s[i].z^=1;
    }
    if(!flag[1]) ans+=calc();
    if(!flag[0])
    {
        for(int i=1;i<=k;i++) if(s[i].x>1&&s[i].y>1)s[i].z^=1;
        ans+=calc();
    }
    cout<<ans%mod;
    return 0;
}

B.寻路

一个二维平面上有很多个矩形,你要从一个给定的点向上下左右任意方向出发,然后只能在矩形的边上或者角上转弯,问到达另一个点的最短路径。

20组数据,每组矩形数量不超过1000

题解:我们考虑最短路,直接建图最多只会有n^2个点,但是它们不全是有用的,所以我们考虑从每一个矩形的角上向四周出发连边,这样最多只有12n个点,跑最短路就行了。建图稍微复杂点。

复杂度Tnlogn

#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#include<queue>
#define ll long long
#define INF 20000000000000LL
#define MN 1000
#define mp(x,y) make_pair((x),(y))
#define pa pair<ll,int>
using namespace std;
inline int read()
{
    int x = 0 , f = 1; char ch = getchar();
    while(ch < ‘0‘ || ch > ‘9‘){ if(ch == ‘-‘) f = -1;  ch = getchar();}
    while(ch >= ‘0‘ && ch <= ‘9‘){x = x * 10 + ch - ‘0‘;ch = getchar();}
    return x * f;
}
int n,cnt,lcnt,cn,head[MN*100];
inline int abs(int x){return x<0?-x:x;}
struct L{
    int l,r,x;
    vector<int> s;
    L(){}
    L(int l,int r,int x):l(l),r(r),x(x){s.clear();}
    bool operator<(const L&b)const{return x<b.x;}
}r[MN*5+5],c[MN*5+5];
struct P
{
    int x,y;
    P(int x=0,int y=0):x(x),y(y){}
    friend int dis(P x,P y){return abs(x.x-y.x)+abs(x.y-y.y);}
    bool operator==(const P&b)const{return x==b.x&&y==b.y;}
}p[MN*MN+5];
bool cmp(int x,int y){return p[x].x==p[y].x?p[x].y<p[y].y:p[x].x<p[y].x;}
struct edge{int to,next,w;}e[MN*100+5];
inline void ins(int f,int t,int w){e[++cn]=(edge){t,head[f],w};head[f]=cn;};
priority_queue<pa,vector<pa>,greater<pa> > q;
ll d[MN*100];bool mark[MN*100];

void dij()
{
    memset(d,127,sizeof(d));memset(mark,0,sizeof(mark));
    d[1]=0;q.push(mp(0,1));
    while(!q.empty())
    {
        int now=q.top().second;q.pop();
        if(mark[now]) continue;mark[now]=1;
        for(int i=head[now];i;i=e[i].next)
            if(d[now]+e[i].w<d[e[i].to])
            {
                d[e[i].to]=d[now]+e[i].w;
                q.push(mp(d[e[i].to],e[i].to));
            }
    }
}

int main()
{
    int T=read();
    while(T--)
    {
        memset(head,0,sizeof(head));
        cnt=lcnt=cn=0;int fx=read(),fy=read(),tx=read(),ty=read();
        p[++cnt]=P(fx,fy);p[++cnt]=P(tx,ty);
        if(fx==tx||fy==ty) ins(1,2,dis(p[1],p[2])),ins(2,1,dis(p[1],p[2]));
        n=read();
        for(int i=1;i<=n;i++)
        {
            int x1=read(),y1=read(),x2=read(),y2=read();
            if(x1>x2) swap(x1,x2);if(y1>y2) swap(y1,y2);
            p[++cnt]=P(x1,y1);p[++cnt]=P(x1,y2);
            p[++cnt]=P(x2,y1);p[++cnt]=P(x2,y2);
            c[++lcnt]=L(cnt-3,cnt-1,y1);r[lcnt]=L(cnt-3,cnt-2,x1);
            c[++lcnt]=L(cnt-2,cnt,y2);r[lcnt]=L(cnt-1,cnt,x2);
        }
        sort(c+1,c+lcnt+1);sort(r+1,r+lcnt+1);
        for(int i=cnt;i;--i)
        {
            int j,id;P now;
            j=lower_bound(c+1,c+lcnt+1,L(0,0,p[i].y))-c-1;
            for(;j&&!(p[c[j].l].x<=p[i].x&&p[c[j].r].x>=p[i].x);--j);
            if(j)
            {
                now=P(p[i].x,c[j].x);
                if(now==p[c[j].l]) id=c[j].l;
                else if(now==p[c[j].r]) id=c[j].r;
                else p[id=++cnt]=now;
                ins(i,id,dis(now,p[i]));
                ins(id,i,dis(now,p[i]));
                c[j].s.push_back(id);
            }
            j=upper_bound(c+1,c+lcnt+1,L(0,0,p[i].y))-c;
            for(;j<=lcnt&&!(p[c[j].l].x<=p[i].x&&p[c[j].r].x>=p[i].x);++j);
            if(j<=lcnt)
            {
                now=P(p[i].x,c[j].x);
                if(now==p[c[j].l]) id=c[j].l;
                else if(now==p[c[j].r]) id=c[j].r;
                else p[id=++cnt]=now;
                ins(i,id,dis(now,p[i]));
                ins(id,i,dis(now,p[i]));
                c[j].s.push_back(id);
            }
            j=lower_bound(r+1,r+lcnt+1,L(0,0,p[i].x))-r-1;
            for(;j&&!(p[r[j].l].y<=p[i].y&&p[r[j].r].y>=p[i].y);--j);
            if(j<=lcnt)
            {
                now=P(r[j].x,p[i].y);
                if(now==p[r[j].l]) id=r[j].l;
                else if(now==p[r[j].r]) id=r[j].r;
                else p[id=++cnt]=now;
                ins(i,id,dis(now,p[i]));
                ins(id,i,dis(now,p[i]));
                r[j].s.push_back(id);
            }
            j=upper_bound(r+1,r+lcnt+1,L(0,0,p[i].x))-r;
            for(;j<=lcnt&&!(p[r[j].l].y<=p[i].y&&p[r[j].r].y>=p[i].y);++j);
            if(j<=lcnt)
            {
                now=P(r[j].x,p[i].y);
                if(now==p[r[j].l]) id=r[j].l;
                else if(now==p[r[j].r]) id=r[j].r;
                else p[id=++cnt]=now;
                ins(i,id,dis(now,p[i]));
                ins(id,i,dis(now,p[i]));
                r[j].s.push_back(id);
            }
        }
        for(int i=1;i<=lcnt;i++)
        {
            sort(c[i].s.begin(),c[i].s.end(),cmp);
            for(int j=1;j<c[i].s.size();j++)
            {
                ins(c[i].s[j],c[i].s[j-1],dis(p[c[i].s[j]],p[c[i].s[j-1]]));
                ins(c[i].s[j-1],c[i].s[j],dis(p[c[i].s[j]],p[c[i].s[j-1]]));
            }
            sort(r[i].s.begin(),r[i].s.end(),cmp);
            for(int j=1;j<r[i].s.size();j++)
            {
                ins(r[i].s[j],r[i].s[j-1],dis(p[r[i].s[j]],p[r[i].s[j-1]]));
                ins(r[i].s[j-1],r[i].s[j],dis(p[r[i].s[j]],p[r[i].s[j-1]]));
            }
        }
        dij();
        if(d[2]<INF) printf("%lld\n",d[2]);
        else puts("No Path");
    }
    return 0;
}  

C题不知道什么鬼,solve=0,貌似数据都是错的,不玩了

时间: 2024-10-12 22:49:06

[APIO2011]的相关文章

BZOJ2303: [Apio2011]方格染色

2303: [Apio2011]方格染色 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 1927  Solved: 744[Submit][Status][Discuss] Description Sam和他的妹妹Sara有一个包含n × m个方格的 表格.她们想要将其的每个方格都染成红色或蓝色. 出于个人喜好,他们想要表格中每个2 ×   2的方形区 域都包含奇数个(1 个或 3 个)红色方格.例如,右 图是一个合法的表格染色方案(在打印稿中,

BZOJ 2303: [Apio2011]方格染色 题解

题目大意: 有n*m的方格,中间的数要么是1,要么是0,要求任意2*2的方格中的数异或和为1.已知一部分格子中的数,求合法的填数的方案数. 思路: 由题意得:a[i][j]^a[i][j+1]^a[i+1][j]^a[i+1][j+1]=1,令这个式子为S(i,j),那么对于某一格(i,j),我们把S(1,1)...S(i,j)异或起来,则可得当i,j均为偶数时a[1][1]^a[i][1]^a[1][j]^a[i][j]=1(于是为了方便先预处理一下),否则a[1][1]^a[i][1]^a[

【bzoj 2303】【Apio2011】方格染色

题目: http://www.lydsy.com/JudgeOnline/problem.php?id=2303 题解: 很神奇的思路,膜一发大佬http://www.cnblogs.com/HHshy/p/5840018.html#undefined 设S(i,j)=a[i][j]^a[i+1][j]^a[i][j+1]^a[i+1][j+1].那么将S(1,1)^S(1,2)^...^S(1,j)^S(2,1)^...^S(2,j)^.....^S(i,j)展开,对于i相同的一行(如S(1,

bzoj 2303: [Apio2011]方格染色

传送门 Description Sam和他的妹妹Sara有一个包含n × m个方格的表格.她们想要将其的每个方格都染成红色或蓝色.出于个人喜好,他们想要表格中每个2 × 2的方形区域都包含奇数个(1 个或 3 个)红色方格.例如,右图是一个合法的表格染色方案(在打印稿中,深色代表蓝色,浅色代表红色) . 可是昨天晚上,有人已经给表格中的一些方格染上了颜色!现在Sam和Sara非常生气.不过,他们想要知道是否可能给剩下的方格染上颜色,使得整个表格仍然满足她们的要求.如果可能的话,满足他们要求的染色

【BZOJ2303】【Apio2011】方格染色 异或方程+并查集

链接: #include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/45081583"); } 题解: 首先我们发现对于 ai,j 有下列式子: ai,j xor ai+1,j xor ai,j+1 xor ai+1,j+1==1 然后推导得到对于 ai,j 有下列式子: a1,1 xor a1,j x

bzoj 2304: [Apio2011]寻路【spfa】

我是智障*3,读优写错了调了半天没发现= = 虽然是个最短路却有网络流一般的神建图啊. 首先发现在拐角处转弯是最优的,于是先离散化,然后矩形的四个顶点向距离它最近的上下左右点连边,跑spfa即可. 就是难写啊,还要判断无解:st在矩形里:dis[t]=inf #include<iostream> #include<cstdio> #include<queue> #include<cstring> #include<algorithm> #incl

BZOJ_2303_[Apio2011]方格染色 _并查集

Description Sam和他的妹妹Sara有一个包含n × m个方格的 表格.她们想要将其的每个方格都染成红色或蓝色. 出于个人喜好,他们想要表格中每个2 ×   2的方形区 域都包含奇数个(1 个或 3 个)红色方格.例如,右 图是一个合法的表格染色方案(在打印稿中,深色代 表蓝色,浅色代表红色) . 可是昨天晚上,有人已经给表格中的一些方格染上了颜色!现在Sam和Sara 非常生气.不过,他们想要知道是否可能给剩下的方格染上颜色,使得整个表格 仍然满足她们的要求.如果可能的话,满足他们

大神刷题表

9月27日 后缀数组:[wikioi3160]最长公共子串 dp:NOIP2001统计单词个数 后缀自动机:[spoj1812]Longest Common Substring II [wikioi3160]最长公共子串 [spoj7258]Lexicographical Substring Search 扫描线+set:[poj2932]Coneology 扫描线+set+树上删边游戏:[FJOI2013]圆形游戏 结论:[bzoj3706][FJ2014集训]反色刷 最小环:[poj1734

做题单

错误 收藏了过多题目 QWQ P1383 高级打字机 P1270 “访问”美术馆 P1481 魔族密码 P1280 尼克的任务 P1271 聚会的快乐 P3631 [APIO2011]方格染色 P1243 排序集合 P2858 [USACO06FEB]奶牛零食Treats for the Cows P3146 [USACO16OPEN]248 P2890 [USACO07OPEN]便宜的回文Cheapest Palindrome P1896 [SCOI2005]互不侵犯 P3154 [CQOI2