题解:P17263 [ICPC 2017 Urumqi R] Friends
lailai0916 · · 题解
题意简述
给定
解题思路
需要判断的是若干函数在同一位置是否取相同值。可以把函数
实现时把它存入编号为
对当前函数集合
若位
加入函数
这个条件具有遗传性。若某个集合已经不合法,继续加入函数只会删除交集中的位,不可能重新变为合法。因此可以在搜索中立即剪去失败分支。
使用极大集合枚举。递归状态除了当前集合
从
当
函数值不需要为每个指数重复快速幂。先迭代计算
搜索得到的集合使用递增函数编号保存,最后直接对整数序列排序即可得到题目要求的字典序。输入中可能重复出现相同的
设搜索访问的合法状态数为
正确性证明
对任意函数集合
加入函数只会把当前交集与另一个位集取交,因此公共位置不会增加。所有被剪枝的集合及其超集都不可能成为朋友圈。递归过滤后的
若递归在
因此搜索不重不漏地得到全部极大朋友圈。最后的标准字典序排序与题目输出顺序一致,算法正确。
参考代码
#include <bits/stdc++.h>
using namespace std;
using pii=pair<int,int>;
const int N=105;
const int M=705;
int p,u;
bitset<M> val[N];
vector<vector<int>>ans;
bool ok(const bitset<M> &f,int x)
{
bitset<M> g=f;
g&=val[x];
return int(g.count())*2>=p;
}
void dfs(bitset<M> f,vector<int> &s,vector<int> c,vector<int> x)
{
if(c.empty()&&x.empty())
{
ans.push_back(s);
return;
}
while(c.size())
{
int v=c.front();
c.erase(c.begin());
bitset<M> g=f;
g&=val[v];
vector<int>nc,nx;
for(auto i:c)
{
if(ok(g,i))nc.push_back(i);
}
for(auto i:x)
{
if(ok(g,i))nx.push_back(i);
}
s.push_back(v);
dfs(g,s,nc,nx);
s.pop_back();
x.push_back(v);
}
}
string solve()
{
int pw[N];
pw[0]=u;
for(int i=1;i<p;i++)pw[i]=1LL*pw[i-1]*u%p;
for(int i=0;i<p;i++)val[i].reset();
for(int i=0;i<p;i++)
{
int v=i;
for(int j=0;j<p;j++)
{
val[j][(v+pw[j])%7*p+i]=1;
v=1LL*v*i%p;
}
}
bitset<M> f;
for(int i=0;i<7*p;i++)f[i]=1;
vector<int>s,c,x;
for(int i=0;i<p;i++)c.push_back(i);
ans.clear();
dfs(f,s,c,x);
sort(ans.begin(),ans.end());
ostringstream out;
for(auto &v:ans)
{
for(int i=0;i<v.size();i++)
{
if(i)out<<' ';
out<<v[i];
}
out<<'\n';
}
return out.str();
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
map<pii,string>mem;
int T;
cin>>T;
while(T--)
{
cin>>p>>u;
pii key={p,u};
if(!mem.count(key))mem[key]=solve();
cout<<mem[key]<<"END"<<'\n';
}
return 0;
}