題目鏈接:bzoj點我:-) 洛谷點我:-) 題目描述: 在C 部落,雙十字是非常重要的一個部落標志。所謂雙十字,由兩條水平的和一條豎直的”1“線段組成,要求滿足以下幾個限制: ·兩條水平的線段不能在相鄰的兩行。 ·豎直線段上端必須嚴格高于兩條水平線段,下端必須嚴格低于兩條水平線段。 ·豎直線段必須將兩條水平線段嚴格劃分成相等的兩半。 ·上方的水平線段必須嚴格短于下方的水平線段。 現在給定一個 R*C的01 矩陣,要求計算出這個 01 矩陣中有多少個雙十字。注意最終的結果可能很大,只要求輸出雙十字的個數 mod 1,000,000,009 的值
輸入格式: 第一行為用空格隔開的兩個正整數 R和C,分別表示01矩陣的行數和列數。輸入文件第二行是一個非負整數N,表示01矩陣中”0“的個數。接下來的N行,每行為用空格隔開的兩個正整數x和y(1<=x<=R,1<=y<=C),表示(x,y)是一個”0“。數據保證N個”0“的坐標兩兩不同。數據保證R,C,N<=10,000,R*C<=1,000,000.(事實上R*C可能稍大于原設定)
輸出格式: D mod 1,000,000,009 的結果,其中D 為要求的 01矩陣中雙十字的個數。
思路: 首先因為R與C不確定,所以我們需要將點們放在一個一維數組中,算算編號就好了 接下來記錄
然后我們枚舉雙十字的下面那個交點,推一推公式:
{注:len是下面橫線的長度,top表示能到達的最上的位置(連續的1),j是上面的橫線的中心位置} 對于一個點
再進一步變形: 1.當(lr[j] <= lr[i]) 貢獻是
現在,需要解決的是所有帶
感想: 啊我是湖南的為什么這么難qwq 這題我初一的時候抄了一遍題解,然后高一又抄了一遍題解。。 比較懷疑小時候到底看懂了沒。。 其實也不是特別難吧,還是可以想一想推一推的 下方程序中的top與解釋有一點點不一樣,是解釋的top-1
代碼:
//miaomiao 2017.2.7#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>using namespace std;#define LL long long#define Set(a, v) memset(a, v, sizeof(a))#define For(i, a, b) for(int i = (a); i <= (int)(b); i++)#define Forr(i, a, b) for(int i = (a); i >= (int)(b); i--)#define N (10000+5)#define NM (1200000+5)const LL MOD = 1e9+9;int n, m, lr[NM], L[NM], R[NM], down[NM];bool is0[NM];struct Tbit{ LL c[N]; void clear(){Set(c, 0);} int lowbit(int x){return x&(-x);} void add(int x, LL v){ while(x < N){c[x] = (c[x]+v)%MOD; x += lowbit(x);} } LL query(int x){ LL ret = 0; while(x > 0){ret = (ret+c[x])%MOD; x -= lowbit(x);} return ret; }}t1, t2, t3;int ID(int x, int y){return m*(x-1)+y;}inline void init(){ For(i, 1, n){ L[ID(i,1)] = !is0[ID(i,1)]; R[ID(i,m)] = !is0[ID(i,m)]; For(j, 2, m) if(!is0[ID(i,j)]) L[ID(i,j)] = L[ID(i,j-1)]+1; Forr(j, m-1, 1) if(!is0[ID(i,j)]) R[ID(i,j)] = R[ID(i,j+1)]+1; For(j, 1, m) if(!is0[ID(i,j)]) lr[ID(i,j)] = min(L[ID(i,j)], R[ID(i,j)])-1; } For(i, 1, m){ down[ID(n,i)] = !is0[ID(n,i)]; Forr(j, n-1, 1) if(!is0[ID(j,i)]) down[ID(j,i)] = down[ID(j+1,i)]+1; Forr(j, n, 1) if(down[ID(j,i)]) down[ID(j,i)]--; }}inline void work(){ int top, now; LL ans = 0; For(j, 1, m){ top = 0; t1.clear(); t2.clear(); t3.clear(); For(i, 1, n){ if(is0[ID(i,j)]){top=i; t1.clear(); t2.clear(); t3.clear(); continue;} now = ID(i,j); ans += t1.query(lr[now])*down[now]%MOD; ans += t2.query(lr[now])*down[now]*lr[now]%MOD; ans += (t3.query(m)-t3.query(lr[now]))*lr[now]*(lr[now]-1)/2*down[now]%MOD; ans %= MOD; if(i==1) continue; now = ID(i-1,j); if(lr[now]){ t1.add(lr[now], -lr[now]*(lr[now]+1)/2%MOD*(i-1-top-1)%MOD); t2.add(lr[now], lr[now]*(i-1-top-1)%MOD); t3.add(lr[now], i-1-top-1); } } }新聞熱點
疑難解答