这次题目相对比较难,后面几个题都是往常压轴题的难度。
Missing a Point
略
Chefina and Swaps
略
Doctor Chef
略
Chef and Dragon Dens
略
LCM Constraints
无限解当且仅当存在一个点没有边相连且存在一个合法方案,可以最后简单特判,下面不考虑这种情况,假定每个点都有边相连。
显然每个质因子可以分开考虑,对某个特定的质因子,相当于给定了 M M M个 max ( A X i , A Y i ) = R i \max(A_{X_i},A_{Y_i})=R_i max(AXi,AYi)=Ri的限制。
这里 R i R_i Ri可以不相同,看起来不太好做,不过注意到若存在 X i = X j X_i=X_j Xi=Xj且 R i < R j R_i<R_j Ri<Rj,则必然有 A X i ≤ R i A_{X_i}\leq R_i AXi≤Ri且 A Y j = R j A_{Y_j}=R_j AYj=Rj,将限制 j j j换成 ( Y j , Y j ) (Y_j,Y_j) (Yj,Yj)是等价的。这个过程可以用BFS完成,中间要不断判断是否有解,无解可以直接终止。
经过上面的处理后,就可以使得每个连通块的所有限制的 R R R都相等,那么可以对每个连通块分开计算了。对于一个连通块,每个点 X X X的状态只有 A X = R A_X=R AX=R或 0 ≤ A X < R 0\leq A_X<R 0≤AX<R两种,而 0 ≤ A X < R 0\leq A_X<R 0≤AX<R的点需要形成一个独立集。
于是问题转化为对于一个大小为 k k k的独立集,有 R k R^k Rk的贡献,问所有独立集的贡献和。这里可以采用一些高效的独立集搜索算法,不过这里的 N N N不太大,使用一个折半状压DP即可。
具体的,将点集分为大小相近的集合 L L L和 R R R,则一个独立集 S = S l ∪ S r S=S_l\cup S_r S=Sl∪Sr( S l ⊆ L , S r ⊆ R S_l\subseteq L,S_r\subseteq R Sl⊆L,Sr⊆R),需要满足 S l S_l Sl和 S r S_r Sr均为独立集,且 N ( S l ) ∩ S r = ∅ N(S_l)\cap S_r=\empty N(Sl)∩Sr=∅( N ( S ) N(S) N(S)为与 S S S相邻的点的集合)。考虑枚举所有 S l S_l Sl,则 S r ⊆ R ∖ N ( S r ) S_r\subseteq R\setminus N(S_r) Sr⊆R∖N(Sr),预处理出所有的 S r S_r Sr并跑一个FMT即可。
单组数据时间复杂度为 O ( ∣ p ∣ ( N ⋅ 2 N 2 + M ) ) \mathcal O(|p|(N\cdot2^{\frac{N}{2}}+M)) O(∣p∣(N⋅22N+M))。
#include <bits/stdc++.h>
#define MOD 1000000007
#define FR first
#define SE second
using namespace std;
typedef long long ll;
typedef pair<int,int> pr;
void fwt(int *p,int len) {
for(int i=1;i<len;i<<=1)
for(int j=0;j<len;j++)
if (j&i) p[j]=(p[j]+p[j^i])%MOD;
}
struct Edge {
int s,t,v,next;
Edge() {
}
Edge(int a,int b,int c,int d):s(a),t(b),v(c),next(d) {
}
bool operator < (const Edge & b) const {
return v<b.v;}
};
Edge e[20005];
int head[40],minn[40];
bool vis1[40],vis2[10005],vis3[40];
queue <int> q;
Edge ee[5][10005];
int num[40],id[40],cnt;
int sumv[1<<20];
ll val[40];
void dfs(int x) {
vis1[x]=1;
num[++cnt]=x;
id[x]=cnt;
for(int i=head[x];i;i=e[i].next)
if (!vis2[(i+1)>>1]&&!vis1[e[i].t]) dfs(e[i].t);
}
int solve(int n,int m,int d) {
memset(head,0,sizeof(head));
memset(minn,0x3f,sizeof(minn));
memset(vis1,1,sizeof(vis1));
memset(vis2,0,sizeof(vis2));
memset(vis3,0,sizeof(vis3));
sort(ee[d]+1,ee[d]+m+1);
int tot=0;
for(int i=1;i<=m;i++) {
int x=ee[d][i].s,y=ee[d][i].t,v=ee[d][i].v;
vis1[x]=vis1[y]=0;
if (x==y) continue;
e[++tot]=Edge(x,y,v,head[x]);
head[x]=tot;
e[++tot]=Edge(y,x,v,head[y]);
head[y]=tot;
minn[x]=min(minn[x],v);
minn[y]=min(minn[y],v);
}
for(int i=1;i<=m;i++) {
int x=ee[d][i].s,y=ee[d][i].t,v=ee[d][i].v;
if (x!=y) continue;
if (minn[x]<v) return -1;
if (minn[x]>v) {
if (vis3[x]) return -1;
minn[x]=v;
}
vis3[x]=1;
}
for(int i=1;i<=n;i++) q.push(i);
while (!q.empty()) {
int x=q.front();q.pop();
for(;;) {
while (head[x]&&vis2[(head[x]+1)>>1]) x=e[head[x]].next;
if (!head[x]||e[head[x]].v<=minn[x]) break;
int y=e[head[x]].t,v=e[head[x]].v;
if (minn[y]<v) return -1;
if (minn[y]>v) {
if (vis3[y]) return -1;
minn[y]=v;
}
q.push(y);
vis3[y]=1;
vis2[(head[x]+1)>>1]=1;
}
}
ll ans=1;
for(int i=1;i<=n;i++)
if (!vis1[i]) {
int v=minn[i];
cnt=0;
dfs(i);
int sz1=(cnt>>1),sz2=cnt-sz1;
memset(sumv,0,sizeof(int)*(1<<sz1));
memset(val,0,sizeof(val));
for(int j=1;j<=cnt;j++) {
int x=num[j];
for(int k=head[x];k;k=e[k].next)
if (!vis2[(k+1)>>1]) {
int u=e[k].t;
val[j-1]|=(1LL<<(id[u]-1));
}
}
for(int j=0;j<(1<<sz1);j++) {
bool ok=1;
ll s=1;
for(int k=0;k<sz1;k++)
if ((j>>k)&1) {
if ((val[k]&j)||vis3[num[k]+1]) {
ok=0;
break;
}
s=s*v%MOD;
}
if (!ok) continue;
sumv[j]=s;
}
fwt(sumv,1