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