AGC043E
抄一下 https://www.luogu.com.cn/article/n32presk,写的非常好。
下面是要把问题转化为一个群论问题。
定义拓扑空间:全集 和它的一个子集族 ,使得 ,且任意有限个元素的交在 中,任意元素(不要求有限或可数)的并在 中。
则称 是拓扑空间, 内元素叫开集,不在的是闭集。
拓扑空间之间的函数 是连续的,当且仅当 ,(数学分析中有形式一样的度量空间上的结论)
对于这道题,不用太在意这个定义,因为 及其子空间的开集概念是熟知的。
下记 为单位圆(就是首尾相接的 )。
对于拓扑空间 ,一条道路是 的函数,一条闭曲线/回路是 的连续函数。
下面一段直接在道路 的意义下说了。
闭曲线 到 存在连续变化,当且仅当存在连续函数 ,使得 ,此时称 同伦。若还满足 ,这称为定端同伦,记为 。
定端同伦关系构成等价类,即 代表和 定端同伦的等价类。
定义道路 的乘积 :把 放在 , 放在 ,显然还是连续;扩展到等价类上,等价类的 是满足
的运算。
对于定点 到自己的回路,这样的等价类和 构成群,其中单位元 ,而把回路翻转构成了逆元。这称为基本群 。
一个拓扑空间 有强形变收缩核 ,当 和一个连续函数 同伦,且同伦函数 满足 (即 内部不变)。这个同伦把 同到了 。
这表明 可以收缩到两个 在一个点上拼起来,记为 。显然, 可以收缩到 ,只需考虑 的结构。
不难看出(?) 。而有:
塞弗特-范坎彭定理:,其中 是群自由积。
所以,。对于本题的条件,记点集为 ;这可以被看作是 及 构成的串集合。
对于 ,考虑嵌入 及其给出的同态 ,这个同态具体是对于 , 成为单位元 ,否则不变,而这些 的自由群就是 。
一个闭曲线是同伦于单位元 的。那么问题变为:
对于一个自由群 ,找出 ,使得 。
首先必须满足 ,并且 。下面构造展示,这也是充要条件。
记两元素的交换子是 。由于同态性,。这有的好性质是 。
记 ,。如果限制为 ,则可构造 满足条件(可以归纳验证)。
进一步地,取出极小的 。则可以验证,
满足条件。总路径长度是 的。
#include<bits/stdc++.h>
using namespace std;
#define pt array<int,2>
struct loop{vector<pt> a;};
loop inv(loop A){reverse(A.a.begin(),A.a.end());return A;}
loop operator *(loop A,loop B){
loop C;
for(auto u:A.a)C.a.push_back(u);
for(int i=1;i<B.a.size();i++)C.a.push_back(B.a[i]);
return C;
}
loop operator ^(loop A,loop B){
return A*B*inv(A)*inv(B);
}
loop w(int x){
loop A;A.a.push_back({0,0});
for(int i=1;i<=x+1;i++)A.a.push_back({i,0});
A.a.push_back({x+1,1});
A.a.push_back({x,1});
for(int i=x;i>=0;i--)A.a.push_back({i,0});
return A;
}
loop w(vector<int> S){
if(S.size()==1)return w(S[0]);
int x=S.back();S.pop_back();
return w(S)^w(x);
}
int A[(1<<6)+5],n;
string str;
vector<int> getS(int x){
vector<int> S;
for(int i=0;i<n;i++)if(x&(1<<i))S.push_back(i);
return S;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>str;
for(int i=0;i<(1<<n);i++)A[i]=str[i]-'0';
int flg=A[0]==1;
for(int i=0;i<(1<<n);i++)for(int j=0;j<(1<<n);j++)if((i&j)==j)flg&=(A[j]>=A[i]);
if(!flg)return cout<<"Impossible"<<endl,0;
cout<<"Possible"<<endl;
loop ans;ans.a.push_back({0,0});
for(int i=0;i<(1<<n);i++){
if(A[i]==1)continue;
bool cf=1;
for(int j=0;j<i;j++)if((i&j)==j&&A[j]==0)cf=0;
if(cf)ans=ans*w(getS(i));
}
cout<<ans.a.size()-1<<endl;
for(auto [x,y]:ans.a)cout<<x<<" "<<y<<endl;
return 0;
}
又快又好写,不知道为什么第一篇点赞更多。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?