模擬賽總結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和改題速度,並且補全知識漏洞。
高斯消元還是非常不熟悉
實力不濟,還要加油!

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