The 3rd Universal Cup. Stage 24: Poland
赛时切了ABGIJK,觉得有价值需要记录一下的只有这两道题。
B
题意简述
没有,简述不了。
思路简述
不妨记 \(f_{0/1/2,i,j}\) 表示从 \(i\) 到 \(j\) 至少携带的行李数是 \(0,1,2\) 个,这时从 \(i\) 到 \(j\) 的最短路。这个东西可以直接通过 floyd 算法快速维护。
于是从 \(i\) 到 \(j\) 的行李搬运就有以下三种情况:
- 直接通过携带 2 个行李的路径从 \(i\) 走到 \(j\),也就是 \(f_{2,i,j}\)
- 首先携带 2 个行李到某个点 \(k\),然后通过 \(k\) 搬运两次走到 \(j\),也就是 \(f_{2,i,k}+f_{1,k,j}+f_{0,j,k}+f_{1,k,j}\)
- 首先通过搬运两次到某个中间点 \(k\),然后携带两个行李直接到 \(j\),也就是 \(f_{1,i,k}+f_{0,k,i}+f_{1,i,k}+f_{2,k,j}\)
将以上情况处理出来的情况称作 \(g_{i,j}\),这里也就处理出了任意两点之间搬运两个行李的最小贡献。
再跑一轮 floyd 也就得到了任意两点之间搬运行李的最短路。
综上,时间复杂度为 \(O(n^3)\)
代码
#include<bits/stdc++.h>
using ll=long long;
using namespace std;
const int N=404;
ll f[3][N][N];
ll g[N][N];
const ll inf=10000000000000999;
void Silverwolf(){
int n,m;
cin>>n>>m;
for(int k=0;k<=2;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
f[k][i][j]=inf;
g[i][j]=inf;
}
}
}
for(int i=1;i<=m;i++){
int a,b,c,d;
cin>>a>>b>>c>>d;
for(int k=0;k<=d;k++){
f[k][a][b]=min(f[k][a][b],1ll*c);
}
}
for(int t=0;t<=2;t++){
for(int i=1;i<=n;i++)f[t][i][i]=0;
}
for(int t=0;t<=2;t++){
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
f[t][i][j]=min(f[t][i][k]+f[t][k][j],f[t][i][j]);
}
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
g[i][j]=f[2][i][j];
for(int k=1;k<=n;k++){
g[i][j]=min(g[i][j],f[2][i][k]+f[1][k][j]+f[0][j][k]+f[1][k][j]);
g[i][j]=min(g[i][j],f[1][i][k]+f[0][k][i]+f[1][i][k]+f[2][k][j]);
}
};
}
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++)g[i][j]=min(g[i][j],g[i][k]+g[k][j]);
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(g[i][j]>=inf)g[i][j]=-1;
cout<<g[i][j]<<' ';
}cout<<'\n';
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
// int T;cin>>T;while(T--)
Silverwolf();
return 0;
}
/*
5 7
1 2 500 2
2 3 100 1
3 5 20 2
5 4 5 1
4 2 1 0
3 4 40 2
5 4 77 1
*/
J
题意简述
给定一个 \(h\times w\) 的 \(01\) 字符串,你可以执行以下三种操作:
- 将 \((i,j)\) 元素翻转
- 将 第 \(i\) 行的元素翻转
- 将 第 \(j\) 列的元素翻转
求经过一系列以上三种操作,以及尚未执行任何操作时,需要至少操作多少次,能使得矩阵变成全 0 矩阵。
思路简述
由于 \(h\leq 8\),那么显然,这是这道题的突破口。
对于每列的 \(01\) 串,可以视作一个 \(0\) 到 \(255\) 的一个二进制编码。
对于任意一列的这样的二进制编码(或 01 串),我的最小次数的操作步骤一定满足如下条件:
- 首先,我将每一行的这样的二进制编码,都将它的值优先变成 \(x\) 或 \(N\oplus x\)。其中 $\oplus $ 表示二进制下的异或符号,而 \(N=2^n -1\),显然 \(N\oplus x\) 表示的是 \(x\) 的反码。
- 假设我最终产生了 \(x\) 的数量为 \(cnt_x\),那么我需要先将这些 \(x\) 都取反变成 \(N\oplus x\),需要的贡献是 \(cnt_x\)。
- 最终,翻转行需要产生的贡献是 \(pop(N\oplus x)\),这表示这个数二进制下 1 的位数。
很好,对于没有任何修改的情况,我们就解决了。
我们可以记录一个东西 \(f_{i,j}\) 表示从 \(i\) 这个数变成 \(j\),再变成 \(j\oplus N\) 需要消耗的最小的贡献。
\(i\) 有两种途径变成 \(j\oplus N\),第一种途径是直接变,贡献是 \(pop(i\oplus (j\oplus N))\)
第二种途径是先变成 \(j\),再整体翻转,贡献是 \(pop(i\oplus j)+1\)
两者取最小值即可处理出 \(f_{i,j}\)。
难道每次询问我们都要枚举一下变成哪个数字 \(x\) 吗?
这不现实。
所以我们可以维护一个 \(dp_x\),表示将所有数变成 \(x\) 所需要的总消耗。既然你 \(f_{i,j}\) 都维护出来了,这样的一个东西也很好维护。
对于第 \(1,3\) 种修改,本质上就是将某个位置的掩码改变一下,因此我们可以删除原有掩码对 \([0,N]\) 所数的贡献,加上一个新的掩码对 \([0,N]\) 的贡献。
对于第 \(2\) 种修改,本质上是对每个掩码都映射到了新的掩码,我们可以将 \(dp[x]\) 的值存到 \(dp[x\oplus 2^i]\) 的位置即可了。
综上所述,我们可以在 \((2^h(2^h +w+q))\) 的时间复杂度内解决这个问题。
代码实现
#include<bits/stdc++.h>
using ll=long long;
using namespace std;
const int N=404;
const ll inf=1e9+7;
void Silverwolf(){
int n,m,q;
cin>>n>>m>>q;
int N=(1<<n)-1;
vector<int>mask(m+1,0);
vector<vector<char>>a(n+1,vector<char>(m+1,0));
vector<int>cnt(N+1,0);
for(int i=0;i<n;i++){
for(int j=1;j<=m;j++){
cin>>a[i][j];
int ch=a[i][j]-'0';
mask[j]+=(1<<i)*ch;
}
}
for(int j=1;j<=m;j++){
cnt[mask[j]]++;
}
vector<vector<int>>f(N+1,vector<int>(N+1,0));
for(int i=0;i<=N;i++){
for(int j=0;j<=N;j++){
f[i][j]=min(__builtin_popcount(i^j)+1,__builtin_popcount(i^j^N));
}
}
vector<int>dp(N+1,0);
for(int i=0;i<=N;i++){
for(int j=0;j<=N;j++){
dp[i]+=cnt[j]*f[j][i];
}
}
auto get_ans=[&]()->int{
int ans=inf;
for(int i=0;i<=N;i++){
ans=min(ans,dp[i]+__builtin_popcount(i^N));
}
return ans;
};
cout<<get_ans()<<'\n';
auto add=[&](int x,int tg,int cnt)->void{
for(int i=0;i<=N;i++){
dp[i]+=cnt*tg*f[x][i];
}
};
int tot=0;
while(q--){
char ch;
cin>>ch;
if(ch=='P'){
int i,j;
cin>>i>>j;
--i;
add(tot^mask[j],-1,1);
cnt[tot^mask[j]]--;
mask[j]^=(1<<i);
cnt[tot^mask[j]]++;
add(tot^mask[j],1,1);
}else if(ch=='K'){
int j;
cin>>j;
add(tot^mask[j],-1,1);
cnt[tot^mask[j]]--;
mask[j]^=N;
cnt[tot^mask[j]]++;
add(tot^mask[j],1,1);
}else{
int i;
cin>>i;
//第 i 行
--i;
tot^=(1<<i);
vector<int>ncnt(N+1,0);
vector<int>ndp(N+1,0);
for(int j=0;j<=N;j++){
ncnt[j^(1<<i)]+=cnt[j];
ndp[j^(1<<i)]=dp[j];
}
cnt=ncnt;
dp=ndp;
}
cout<<get_ans()<<'\n';
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
// int T;cin>>T;while(T--)
Silverwolf();
return 0;
}
/*
3 4 6
1010
1101
0010
R 2
P 3 1
K 2
P 2 1
K 4
P 3 4
*/
浙公网安备 33010602011771号