題目描述
考慮以下在 \(m\) 維空間的遊走過程:初始時你在原點,即每一維座標為 \(0\) 的位置。接下來依次有 \(\sum_^m t_i\) 次操作,分為 \(m+1\) 個階段。第 \(0\) 個階段有 \(t_0\) 次操作,每次操作可以不動或者選擇任意一維向其正方向前進 \(1\) 個單位長度。第 \(i(1\leq i\leq m)\) 個階段有 \(t_i\) 次操作,每次操作可以不動或者提公升 \(i\) 點疲倦度的同時向第 \(i\) 維負方向前進 \(1\) 個單位長度。
設 \(f(x)\) 表示所有操作結束後回到遊走起點的方案中疲勞度為 \(x\) 的方案數,定義兩個方案不同當且僅當某一次操作的決策不同。你需要求 \(\sum_^\\) 的值。
多組資料:\(1\leq t\leq 200\),\(1\leq m\leq 10,1\leq t_i<2^\)
解法
設 \(x_i\) 表示最終向第 \(i\) 維走了 \(x_i\) 步,那麼它對應的方案數是:
\[\prod_^m \cdot
\]那麼貢獻為 \(1\) 的充要條件是:\(t_i\and x_i=x_i\),\(\\) 是 \(t_0\) 二進位制位的拆分。後面的性質可以用歸納法證明,首先要滿足 \(t_0\and x_1=x_1\),那麼 \(x_1\) 相當於把 \(t_0\) 的二進位制位拆了一些出來,\(x_2\) 繼續拆分 \(t_0-x_1\),那麼就可以證明了。
那麼我們考慮規劃合法的 \(\\),不同的方案以疲勞度來區分。考慮疲勞度是 \(\sum_^m x_i\cdot i\),那麼我們依次考慮 \(t_0\) 的每個二進位制位,再決策這一位分配給 \(x\) 的 \(0\sim m\) 的哪乙個即可(如果分配 \(0\) 代表這一位不選),對於以前的位都相同的方案,我們在第乙個導致數字不同的地方它們區分出來。
設 \(dp[i][s]\) 表示考慮前 \(i\) 位,進製到 \(2^\) 的集合是 \(s\)(如果 \(s_j=1\) 代表進製得到 \(j\cdot 2^\) 是可行的)的方案數,那麼轉移考慮列舉 \(t_0\) 第 \(i\) 位要分配給 \(0\sim m\) 中的哪乙個。注意兩種方案如果此後進製還是相同那麼需要抵消,所以我們可以維護兩個集合 \(s_1,s_2\),表示第 \(i\) 位疲勞值是 \(1/0\) 轉移到的狀態,用異或的方式來抵消即可。
時間複雜度 \(o(t\cdot 2^\cdot m^2\cdot \log t)\)
#include #include #include using namespace std;
const int m = 50;
#define int long long
int read()
while(c>='0' && c<='9')
return x*f;
}int t,n,m,t[m],vis[m],mp[m][m],dp[m][1<<10];
void work()
n=0;while(t[0]) vis[n++]=t[0]&1,t[0]>>=1;
for(int i=0;i>k&1)
for(int l=0;l<=up;l++) if(mp[i][l])
dp[w][s1]+=dp[w^1][j];
dp[w][s2]+=dp[w^1][j];
} }for(int i=0;i>j&1) ans+=dp[w][i];
printf("%lld\n",ans);
}signed main()
題目描述
\(1\leq n\leq 150,1\leq m\leq 30,0\leq w[i][j]\leq 100\)
解法
考慮最後答案的形式:若干個哈密頓圈,轉角的點會產生貢獻。
顯然哈密頓圈是 \(\tt np\) 問題,但因為這是平面圖,所以關鍵性質是它可以黑白染色。
那麼我們把平面圖黑白染色,嘗試轉化為二分圖問題。首先考慮如何判定,可以給每個需要覆蓋的點(下文稱之為關鍵點) \(2\) 的流量,如果兩個關鍵點相鄰那麼連一條流量為 \(1\) 的邊,對它跑網路流,滿流是有解的充要條件。
那麼我們考慮魔改上面的圖來完成最大化權值的目的,注意到彎道是豎直方向和水平方向的拼接,那麼我們可以考慮拆點,對於每個 \(x\) 我們再新建 \(x_1,x_2\) 表示豎直點和水平點,那麼我們在同時選取豎直點和水平點的時候計算貢獻:
上圖展示了建圖的一部分,另一部分是:如果 \(x,y\) 豎直相連,那麼把 \(x_1,y_1\) 連一條流量為 \(1\) 的邊;如果 \(x,y\) 水平相連,那麼把 \(x_2,y_2\) 連一條流量為 \(1\) 的邊。然後我們對這個圖跑最小費用流,再用總權值去減就可以得到答案。因為如果同時使用 \(x_1,x_2\) 得到的權值是 \(0\) 最後的貢獻就是 \(w\),如果只使用一邊那麼最後的貢獻是 \(0\)
好像這題只有 \(\tt spfa\) 才能通過 \(...\)
#include #include #include using namespace std;
const int m = 20005;
const int inf = 0x3f3f3f3f;
int read()
while(c>='0' && c<='9')
return x*f;
}int n,m,a[155][35],b[155][35],id[155][35][3];
int tot,s,t,ans,f[m],dis[m],flow[m],pre[m],lst[m];
int dx[4]=,dy[4]=;
struct edgee[m*100];
void add(int u,int v,int f,int c)
,f[u]=tot;
e[++tot]=edge,f[v]=tot;
}int bfs()
} }return flow[t]>0;
}signed main()
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
b[i][j]=read();
int a=0,b=0,sum=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(a!=b)
s=0;t++;tot=1;
//build the graph
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++) if(i+j&1)
for(int k=0;k<4;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++) if(!a[i][j])
else
}while(bfs()) }
if(sum)
printf("%lld\n",ans);
}
省選集訓2022 模擬賽6
題目描述 定義長度為 n 的好串 s 滿足 給你長度為 n 的序列 a 和 v 分別表示原序列和價值序列。你每次可以選擇乙個原序列中的好串,將其刪除之後剩下的串會前後拼接。設這次刪除的長度是 l 那麼會得分 v l 問最大得分,不一定要把原序列刪完。n leq 400,v i leq 10 5,a ...
省選集訓2022 模擬賽8
題目描述 給定乙個 n times m 的 01 矩陣,對於矩陣的每乙個位置,你需要對於這個位置上的值反轉,然後求出這個矩陣的秩的變化 0 可以將這個矩陣看成 n 個大小為 0,2 m 的數,秩就是它們線性基的大小。n,m leq 1000 解法 我們判斷求出原先的 n 個向量在原來的線性基中是可以...
省選集訓2022 模擬賽10
題目描述 給定 n 個元素,每個元素有兩個屬性值 a i,b i 我們可以將其以任意順序排列,要最大化下式 min a i i cdot k max b i i cdot k n leq 10 5,a i,b i,kn leq 10 9 解法 應該是遇到困難退大火才對,直接使用列舉法,考慮列舉 m ...