不難發現行和列是獨立的,也就是其實我們把行和列的摺紙順序任意交換都是可以的。
那麼乙個矩形可以被摺出的充要條件是它四條邊分別所在的行或列都可以通過若干次摺疊得到。比方說矩形左邊那列假設是第 \(i\) 列,那麼只有 \(1\sim i\) 的紙都可以折到右邊去這個矩形才可能被摺出。
手畫一下不難證明一些細節。由於並不好用自然語言描述就懶了。
考慮設 \(f_\) 表示第 \(i\) 行(列)能否從左右(上下)折過來。根據上面摺疊順序可以交換的結論,我們可以把每一行的 hash 值求出來跑 manacher。然後易得能貢獻到 \(f_\) 的是 \([i-p_i,i)\) 這段區間,如果這段區間至少有乙個 \(1\) 就可以。直接用字首和就可以優化到 \(o(n+m)\)。
統計答案時列舉矩形左上角,我們只需要知道右下方有多少個點滿足 \(f_=f_=1\),字尾和即可。
時間複雜度 \(o(nm)\)。
#include using namespace std;
typedef unsigned long long ull;
const int n=2000010;
const ull base=13331;
int n,m,p[n];
ull ans,a[n],b[n],s[n],f[5][n],g[n];
char ch;
unordered_mapvis;
void manacher(ull *s,int len)
}int main()
ull rd1=rand(),rd2=rand(),rd3=rand();
while (vis[rd1]) rd1=rand();
while (vis[rd2]) rd2=rand();
while (vis[rd3]) rd3=rand();
for (int i=1;i<=n;i++)
s[2*i]=a[i],s[2*i-1]=rd1;
s[0]=rd2; s[2*n+1]=rd1; s[2*n+2]=rd3;
manacher(s,2*n+1);
memset(g,0,sizeof(g));
f[1][1]=g[1]=1;
for (int i=4;i<=2*n;i+=2)
memset(g,0,sizeof(g));
f[2][n]=g[n]=1;
for (int i=2*n-2;i>=1;i-=2)
for (int i=1;i<=m;i++)
s[2*i]=b[i],s[2*i-1]=rd1;
s[0]=rd2; s[2*m+1]=rd1; s[2*m+2]=rd3;
manacher(s,2*m+1);
memset(g,0,sizeof(g));
f[3][1]=g[1]=1;
for (int i=4;i<=2*m;i+=2)
memset(g,0,sizeof(g));
f[4][m]=g[m]=1;
for (int i=2*m-2;i>=1;i-=2)
for (int i=n;i>=1;i--) f[2][i]+=f[2][i+1];
for (int i=m;i>=1;i--) f[4][i]+=f[4][i+1];
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
if (f[1][i] && f[3][j])
ans+=f[2][i]*f[4][j];
cout<
return 0;
}
9 6摺紙問題
題目 請把一段紙豎著放在桌子上,然後從紙條的下邊向上方對折1次,壓出摺痕後展開。此時摺痕是凹下去的,即摺痕突起的方向指向紙條的背面。如果從紙條的下邊向上方連續對折兩次,壓出摺痕後展開,此時有三條摺痕,從上到下依次是下摺痕 下摺痕和上摺痕。給定乙個輸入引數n,代表紙條都從下邊向上方連續對折n次,請從上...
基礎17 摺紙問題
17 摺紙問題 問題描述 已知有一張紙,其厚度為1厘公尺。現在給你一座山的高度n 單位 公尺 問將紙對折多少次後,其厚度將超過這座山的高度?輸入說明 你的程式需要從標準輸入裝置 通常為鍵盤 中讀入多組測試資料。每組輸入資料由一行組成,每行為乙個正整數n,n小於等於珠穆朗瑪峰的高度。輸出說明 對每組測...
嵊州D5T2 摺紙 folding
問題描述 在非常緊張的 noip 考試中,有人喜歡啃指甲,有人喜歡轉鉛筆,有人喜歡撕 紙條,而小 x 喜歡迷摺紙。現有乙個 w h 的矩形紙張,監考老師想知道,小 x 至少要折多少次才能使 矩形紙張變成 w h 的矩形紙張。注意,每次的摺痕都要平行於紙張的某一條邊。輸入格式 第一行包括兩個整數 w,...