模拟赛总结B 【CQOI2004】

T1【CQOI2014】和谐矩阵

Description

我们称一个由0和1组成的矩阵是和谐的,当且仅当每个元素都有偶数个相邻的1.一个元素相邻的元素包括它本身,及他上下左右的4个元素(如果存在)。
给定矩阵的行数和列数,请计算并输出一个和谐的矩阵。注意:所有元素为0的矩阵是不允许的。

Input

输入一行,包含两个空格分隔的整数m和n,分别表示矩阵的行数和列数。

Output

输出包含m行,每行n个空格分隔整数(0或1),为所求矩阵。测试数据保证有解。

Sample Input

4 4

Sample Output

0 1 0 0
1 1 1 0
0 0 0 1
1 1 0 1

Solution
这道题有两种做法,一种是高斯消元解异或方程组,一种是优美的搜索,网上基本上所有的做法都是解异或方程组,我就讲一下如何用优美的搜索来做。
可以发现我们只要枚举出第一行的状态就可以计算出剩下的每一行,但是这样做只能拿到60分,因为最坏情况的复杂度是o(2^40)次方的。
我们发现这个矩阵有一种神奇的对称性,因为我们只需要枚举第一行的一半,另一半用前一半翻折过去就可以了。但是这样还是不行,只能拿到85分左右,因为如果我们o(nm)的判断答案可行性是很劣的,所以我们用类似状压的方法,f[i]是一个二进制状态,那么f[i+1]就等于f[i]^(f[i]<<1)^(f[i]>>1)^(f[i-2])
这样子就可以通过本题了。
(吐槽:一个变量名打错,调了一个多小时)

T2 【CQOI2014】危桥

Description

Alice和Bob居住在一个由N座岛屿组成的国家,岛屿被编号为0到N-1。某些岛屿之间有桥相连,桥上的道路是双向的,但一次只能供一人通行。其中一些桥由于年久失修成为危桥,最多只能通行两次。
Alice希望在岛屿a1和a2之间往返an次(从a1到a2再从a2到a1算一次往返)。同时,Bob希望在岛屿b1和b2之间往返bn次。这个过程中,所有危桥最多通行两次,其余的桥可以无限次通行。请问Alice和Bob能完成他们的愿望吗?

Input

本题有多组测试数据。

每组数据第一行包含7个空格隔开的整数,分别为N、a1、a2、an、b1、b2、bn。

接下来是一个N行N列的对称矩阵,由大写字母组成。矩阵的i行j列描述编号i-1和j-1的岛屿间的连接情况,若为“O”则表示有危桥相连;为“N”表示有普通的桥相连;为“X”表示没有桥相连。

Output

对于每组测试数据输出一行,如果他们都能完成愿望输出“Yes”,否则输出“No”。

Sample Input

4 0 1 1 2 3 1
XOXX
OXOX
XOXO
XXOX
4 0 2 1 1 3 2
XNXO
NXOX
XOXO
OXOX

Sample Output

Yes
No

Data Constraint

4<=N<=50
0<=a1,a2,b1,b2<=N-1
1<=an,bn<=50

Solution

这一题是一道网络流。
首先建立超级源和超级汇,然后s向a1,a2连一条边权为an,bn的边,a2,b2向t连一条边权为an,bn的边,再去跑一遍最大流,再判断maxflow是否大于等于(an+bn)
但是这样显然是有问题的,会有从a1到b2,a2到b1的情况出现,因此我们再交换b1,b2,跑一遍最大流就可以了。

T3【CQOI2014】通配符匹配

Description

几乎所有操作系统的命令行界面(CLI)中都支持文件名的通配符匹配以方便用户。最常见的通配符有两个,一个是星号(”“’),可以匹配0个及以上的任意字符:另一个是问号(”?“),可以匹配恰好一个任意字符。现在需要你编写一个程序,对于给定的文件名列表和一个包含通配符的字符串,判断哪些文件可以被匹配。

Input

第一行是一个由小写字母和上述通配符组成的字符串。第二行包含一个整数n,表示文件个数。接下来n行,每行为一个仅包含小写字母字符串,表示文件名列表。

Output

输出n行,每行为”YES“或”NO“,表示对应文件能否被通配符匹配。

Sample Input

*abc?e**e
3 abcee
ppabcqexe
abcdefgee

Sample Output

NO
YES
YES

Solution

这一题是一道神奇的dp题。
我们定义f[i][j]表示使用到第i个通配符匹配到读入字符串的第j位,预处理一个p数组,p[t]表示第t个通配符出现的位置。
一个通配符可以把字符串分隔开,只需要确保中间的位置是相同的就可以了,这可以用hash来判断。dp方程写在代码里了,就不在赘述。

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
int n,i,j,a[50];
int m;
ll f[50],q[50];
bool fl;
inline int check(){
    int x=1;
    int i,j,t;
    fo(i,x+1,n+1) {
        f[i]=(f[i-1]>>1)^(f[i-2])^(f[i-1]<<1)^f[i-1];
        if (f[i]>((ll)(q[m]-1))) f[i]-=(q[m]);
    }
    if (f[n+1]==0) return 1;
  return 0;
}
void fill(int x){
    int i;
    if (fl) return;
    if (x==(m/2+1+(m)%2)){
        fd(i,m,x) a[i]=a[m-i+1];
        f[1]=0;
        fo(i,1,m) if (a[i]==1) f[1]+=(q[i-1]); 
        if (!check()) return;
          else {
            fl=true;
            return;
          } 
    }
    a[x]=1;
    fill(x+1);
    //if (fl) return;
    a[x]=0;
    fill(x+1);
//  if (fl) return;
}
int main(){
    //freopen("1.in","r",stdin);
    //freopen("1.out","w",stdout);
    scanf("%d%d",&n,&m);
    q[0]=1;
    fo(i,1,45) q[i]=q[i-1]*2; 
    fill(1);
    fo(i,1,n) {
      fo(j,1,m) 
        if (f[i]&(q[j-1])) printf("1 "); else printf("0 ");
      printf("\n");}
}
#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int inf=10000007;
const int maxn=200050;
int n,i,j,a1,a2,an,b1,b2,bn,fl,tot,s,t;
int d[300],q[300],next[maxn],b[maxn],head[maxn],c[maxn],cur[maxn];
char a[100][100];
void plus(int x,int y,int z){next[++tot]=head[x];head[x]=tot;b[tot]=y;c[tot]=z;}
void add(int x,int y,int z){plus(x,y,z); plus(y,x,0);}
int bfs(){
    int x,l,r,i;
    l=0,r=1; q[r]=s;
    memset(d,0,sizeof(d));
    d[s]=1;
    while (l<r){
        x=q[++l];
        for(i=head[x];i!=-1;i=next[i]){
            if (d[b[i]]==0&&c[i]!=0) {
                d[b[i]]=d[x]+1;
                q[++r]=b[i];
            }
        }
    }
    return d[t];
}
int dfs(int x,int f){
    int i;
    if (x==t) return f;
    for (int &i=cur[x];i!=-1;i=next[i]){
        if (d[b[i]]==d[x]+1&&c[i]!=0) {
            int di=dfs(b[i],min(c[i],f));
            if (di>0) {
                c[i]-=di;
                c[i^1]+=di;
                return di;
            }
        }
    }
    return 0;
}
void dinic(){
    int i,j,ans;
    tot=-1; s=0,t=n+1;
    memset(head,-1,sizeof(head));
    memset(next,-1,sizeof(next));
    memset(c,0,sizeof(c));
    add(s,a1,an),add(a2,t,an);
    add(s,b1,bn),add(b2,t,bn);
    fo(i,1,n)
      fo(j,1,n) {
        if (a[i][j]=='O') add(i,j,1);
        if (a[i][j]=='N') add(i,j,inf);
      }
    ans=0;
    while (bfs()) {
        fo(i,s,t) cur[i]=head[i];
        while (int di=dfs(s,inf)) ans+=di;
    }
    if (ans>=an+bn) fl=1; else fl=-1;
}
int main(){
    //freopen("1.in","r",stdin);
    //freopen("1.out","w",stdout);
    while (scanf("%d",&n)!=EOF){
        scanf("%d%d%d%d%d%d",&a1,&a2,&an,&b1,&b2,&bn);
        a1++,a2++,b1++,b2++;
        scanf("%d\n");
        fo(i,1,n) {
            fo(j,1,n)
              scanf("%c",&a[i][j]);
            scanf("\n"); 
        }
        fl=-1;
        dinic();
        swap(b1,b2);
        if (fl==1) dinic();
        if (fl==1) printf("Yes\n"); else printf("No\n");
    }
} 
#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define ull unsigned long long
#define seed 131 
using namespace std;
const int maxn=100010;
int i,n,len,j,t,f[12][maxn],p[12];
ull hash[maxn][2],q[maxn];
char s[maxn],st[maxn];
void Hash(char str[],int opt)
{
    int len=strlen(str+1);
    for (int i=1; i<=len; i++) hash[i][opt]=hash[i-1][opt]*seed+str[i];
}
ull get(int l,int r,int rt){
    if (l>r) return -1;
    return hash[r][rt]-hash[l-1][rt]*q[r-l+1];
}
int main(){
    //freopen("1.in","r",stdin);
    //freopen("1.out","w",stdout);
    scanf("%s",s+1);
    Hash(s,0);
    q[0]=1;     
    fo(i,1,maxn-1) q[i]=q[i-1]*seed;
    len=strlen(s+1);
    fo(i,1,len) if (s[i]=='?'||s[i]=='*') p[++t]=i;
    len++,s[len]='?',p[++t]=len;
    scanf("%d",&n);
    while (n) {
        n--;
        scanf("%s",st+1); Hash(st,1);
        memset(f,0,sizeof(f)); f[0][0]=1;
        len=strlen(st+1);
        st[++len]='%';
        fo(i,0,t-1) {
            if (s[p[i]]=='*') fo(j,1,len) if (f[i][j-1]) f[i][j]=1;
            fo(j,0,len){
                if (f[i][j]&&get(j+1,j+p[i+1]-p[i]-1,1)==get(p[i]+1,p[i+1]-1,0)) 
                  if (s[p[i+1]]=='?') f[i+1][j+p[i+1]-p[i]]=1;
                    else f[i+1][j+p[i+1]-p[i]-1]=1;
            }
        }
        if (f[t][len]) printf("YES\n"); else printf("NO\n");
    }
}

总结

今天这场比赛的发挥还是不错的,拿到了140分,以自己目前的水平来说基本上是完全发挥出来了,现在一周只有一场比赛打,一定要珍惜这宝贵的比赛机会,同时提升codlity和改题速度,并且补全知识漏洞。
高斯消元还是非常不熟悉
实力不济,还要加油!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章