1 条题解
-
0
题解
把原图和碎片看作由若干非空格单元组成的集合,允许水平/垂直翻转、 的倍数旋转。只要三片碎片的变换后单元集合恰好覆盖原图、字符也一一对应且不重叠,即为可行方案。
预处理与表示
- 读入原图,提取所有非
.单元,记录坐标与字符,并给每个单元编号id。用FULL位集表示全部目标单元。 - 对每个碎片生成 8 个方向(4 次旋转 × 是否水平翻转),提取非空单元并归一化到以左上为 。去重相同朝向。
- 为了枚举位置:选该朝向的第一个单元作为锚点,枚举所有原图中字符相同的单元作为锚点对齐位置,平移后检查所有单元是否仍在原图内、字符匹配。若合法,生成一个位集(长度为
|FULL|),并去重后存入该碎片的可行摆放列表。
位集用
vector<uint64_t>存储,支持与/或、异或等操作。计数
若用暴力三层循环会超时。利用“先存两片并集,再配第三片”的思路:
- 维护哈希表
pairMap:键为两片不重叠摆放的并集位集,值为这种并集出现的次数。 - 依次作为第三片枚举碎片
k(顺序 0..K-1):- 对于
k的每个摆放P_k,计算补集need = FULL ^ P_k。若pairMap中存在键为need的项,说明存在两片(索引均小于k)的并集恰好覆盖剩余部分且与P_k不重叠,于是把计数累加进答案。 - 随后把当前碎片
k与所有更早碎片i<k的摆放两两尝试合并:若不相交,则把它们的并集加入pairMap计数。这保证后续更大的k查询时,pairMap里只包含索引小于当前的两片组合,避免重复计数。
- 对于
复杂度取决于合法摆放数量。典型数据下摆放数不大,位集操作为 ,整体可在限时内通过。
#include <bits/stdc++.h> using namespace std; struct VecHash{ size_t operator()(const vector<uint64_t>& v)const noexcept{ size_t h=0; for(uint64_t x:v) h^=x+0x9e3779b97f4a7c15ULL+(h<<6)+(h>>2); return h; } }; struct Cell{int r,c;char ch;}; vector<string> rot(const vector<string>& g){int R=g.size(),C=g[0].size();vector<string> r(C,string(R,'.'));for(int i=0;i<R;++i)for(int j=0;j<C;++j)r[j][R-1-i]=g[i][j];return r;} vector<string> flip(const vector<string>& g){auto r=g;for(auto& row:r) reverse(row.begin(),row.end());return r;} vector<vector<string>> gen(const vector<string>& g){ vector<vector<string>> m; auto cur=g; for(int k=0;k<4;++k){m.push_back(cur);cur=rot(cur);} cur=flip(g); for(int k=0;k<4;++k){m.push_back(cur);cur=rot(cur);} vector<vector<string>> u; for(auto& x:m){bool same=false;for(auto& y:u) if(y==x){same=true;break;} if(!same) u.push_back(x);} return u; } vector<Cell> cells(const vector<string>& g){ int R=g.size(),C=g[0].size(); vector<Cell> v; int mr=R,mc=C; for(int i=0;i<R;++i)for(int j=0;j<C;++j)if(g[i][j]!='.'){v.push_back({i,j,g[i][j]});mr=min(mr,i);mc=min(mc,j);} for(auto& c:v){c.r-=mr; c.c-=mc;} sort(v.begin(),v.end(),[](const Cell&a,const Cell&b){return a.r!=b.r?a.r<b.r:a.c!=b.c?a.c<b.c:a.ch<b.ch;}); return v; } int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); int K; if(!(cin>>K)) return 0; int R0,C0; cin>>R0>>C0; vector<string> tgt(R0); for(auto& s:tgt) cin>>s; vector<vector<string>> raw(K); for(int i=0;i<K;++i){int R,C;cin>>R>>C; raw[i].resize(R); for(auto& s:raw[i]) cin>>s;} auto tcell=cells(tgt); int tot=tcell.size(); if(tot==0){cout<<0<<'\n'; return 0;} unordered_map<long long,int> id; vector<char> tch(tot); vector<vector<pair<int,int>>> byc(256); for(int i=0;i<tot;++i){long long key=((long long)tcell[i].r<<32)^(unsigned long long)tcell[i].c; id[key]=i; tch[i]=tcell[i].ch; byc[(unsigned char)tcell[i].ch].push_back({tcell[i].r,tcell[i].c});} int BL=(tot+63)/64; vector<uint64_t> FULL(BL,~0ULL); if(tot%64) FULL.back()=(1ULL<<(tot%64))-1; vector<vector<vector<uint64_t>>> place(K); for(int idx=0;idx<K;++idx){ auto mats=gen(raw[idx]); unordered_set<vector<uint64_t>,VecHash> seen; for(auto& m:mats){ auto cs=cells(m); if(cs.empty()) continue; auto anchor=cs[0]; auto& cand=byc[(unsigned char)anchor.ch]; for(auto [tr,tc]:cand){ int dr=tr-anchor.r, dc=tc-anchor.c; vector<uint64_t> bits(BL,0); bool ok=true; for(auto& c:cs){ int nr=c.r+dr,nc=c.c+dc; if(nr<0||nr>=R0||nc<0||nc>=C0){ok=false;break;} long long key=((long long)nr<<32)^(unsigned long long)nc; auto it=id.find(key); if(it==id.end()||tch[it->second]!=c.ch){ok=false;break;} int idv=it->second; bits[idv>>6]|=1ULL<<(idv&63); } if(ok && seen.insert(bits).second) place[idx].push_back(move(bits)); } } } auto disjoint=[](const vector<uint64_t>& a,const vector<uint64_t>& b){for(size_t i=0;i<a.size();++i) if(a[i]&b[i]) return false; return true;}; auto uni=[](const vector<uint64_t>& a,const vector<uint64_t>& b){vector<uint64_t> r(a.size()); for(size_t i=0;i<a.size();++i) r[i]=a[i]|b[i]; return r;}; auto comp=[&](const vector<uint64_t>& a){vector<uint64_t> r(a.size()); for(size_t i=0;i<a.size();++i) r[i]=FULL[i]^a[i]; return r;}; long long ans=0; unordered_map<vector<uint64_t>, long long, VecHash> pairMap; for(int k=0;k<K;++k){ for(auto& pk:place[k]){auto need=comp(pk); auto it=pairMap.find(need); if(it!=pairMap.end()) ans+=it->second;} for(int i=0;i<k;++i) for(auto& pi:place[i]) for(auto& pk:place[k]) if(disjoint(pi,pk)){auto u=uni(pi,pk); pairMap[u]++;} } cout<<ans<<'\n'; return 0; } - 读入原图,提取所有非
- 1
信息
- ID
- 5721
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 7
- 标签
- 递交数
- 4
- 已通过
- 1
- 上传者