被称作永恒之物 在交替更迭中徒劳地缝补 被称作易逝之物 书写了十四行啼哭
test34
6-A 序列游戏 (game.cpp)
感觉和昨天 t1 差不多,但是我更喜欢这个。无限次操作先上一个配鼠定理,可以 \(+a/+b\) 改成可以 \(+(d=\gcd\{a,b\})\)。
发现可以把 \(c\) 改成 \(\mod{d}\) 意义下的来简化问题,之后你枚举新的最小值是哪个,答案就是 \(\min\{\max(c_n-c_1,c_{i-1}+d-c_i)\}\)。
#include<bits/stdc++.h>
#define int long long
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
using namespace std;
const int N=100005;
int T, n, a, b, c[N], Ans;
void mian() {
cin >> n >> a >> b;
int d=__gcd(a,b);
up(i,1,n) {
cin >> c[i];
c[i]=(c[i]%d+d)%d;
}
sort(c+1,c+1+n);
Ans=c[n]-c[1];
up(i,2,n) Ans=min(Ans,c[i-1]+d-c[i]);
cout << Ans << '\n';
}
signed main() {
// freopen("1.txt","r",stdin);
freopen("game.in","r",stdin);
freopen("game.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cin >> T;
while(T--) mian();
return 0;
}
6-B 串饺子 (jiaozi.cpp)
观察,先看一下哪些选择会冲突,显然冲突的满足 \(G\) 在一条 \(y-x\) 一定的直线上。现在只用考虑斜线上怎么做,好像不太好直接确定,那么考虑 dp,设 \(f[i][j][0/1/2]\) 表示选到 \((i,j)\) 当前点没选/选了横的/选了竖的,转移是好转移的。
我本来都觉得这个题目记录多位是必要的,但是看到有学弟给出了直接贪心的做法。竖着的显然都不冲突,先将所有竖着的都拿了,然后考虑拿横着的,如果存在冲突的,就去掉最左边的那一个竖列,然后不管别的加上这个点的贡献。
我捏了一个证明,相互干扰的匹配在一条对角线上,我们单独考虑一条对角线,给 \(\text{G}\) 按顺序标号,设以第 \(i\) 个 \(\text{G}\) 为中点横着/竖着的 RGW 为 \(L_i/R_i\),当然也有可能不存在。
给可能冲突的点 \(L_i/R_i\) 连边,可能有的边包括 \((L_i,R_i),(L_i,R_{i-1}),(L_i,R_{i+1})\),你现在要求最大独立集,这个相当于总点数-最大匹配,而这个图你按顺序匹配小的,贪心求出来的肯定是最大匹配。
#include<bits/stdc++.h>
#define int long long
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
using namespace std;
const int N=3005;
int n, m, Ans, f[N][N][3];
bool x[N][N], y[N][N];
char str[N][N];
signed main() {
// freopen("1.txt","r",stdin);
freopen("jiaozi.in","r",stdin);
freopen("jiaozi.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m;
up(i,1,n) cin >> (str[i]+1);
up(i,1,n) up(j,1,m) {
f[i][j][0]=max(f[i-1][j+1][0],max(f[i-1][j+1][1],f[i-1][j+1][2]));
if(str[i][j]!='G') continue;
x[i][j]=(str[i][j-1]=='R'&&str[i][j+1]=='W');
y[i][j]=(str[i-1][j]=='R'&&str[i+1][j]=='W');
if(x[i][j]) {
f[i][j][1]=max(f[i-1][j+1][0],f[i-1][j+1][1])+1;
}
if(y[i][j]) {
f[i][j][2]=max(f[i-1][j+1][0],f[i-1][j+1][2])+1;
}
// cout << "check " << i << ' ' << j << " = " << f[i][j][0] << ' ' << f[i][j][1] << ' ' << f[i][j][2] << '\n';
}
up(i,1,n) up(j,1,m) if(i==n||j==1) Ans+=max(f[i][j][0],max(f[i][j][1],f[i][j][2]));
cout << Ans << '\n';
return 0;
}
6-C 拖拉机 (tractor.cpp)
"可能经过的"后面加个"最大值"是何意味,这个很难不读错吧,读错了之后一丝非乱搞的思路都没有。
先思考 \(l_i<r_i,l_i\uparrow,r_i\uparrow\) 带来什么,将区间看作点,这个好像差不多完全等价于能转移的区间的左右端点单调吧,所以就是第一问除了最后一跃可以暴力跳到最右边,直接上一个倍增就解决了。现在考虑第二问怎么做,考虑第 \(i=1,\dots,step-1\) 跳可以跳到哪些特殊点,设 \(f(x,i)/g(x,i)\) 表示从 \(x\) 开始像左/右跳 \(i\) 步去到哪,那么可能的第 \(i\) 步就是在 \([g(r,step-i),f(l,i)]\) 了喵显然一个点只有可能成为唯一 \(i\) 的合法区间,所以直接前缀和掉贡献、差分拆开了算就可以了 qwq
#include<bits/stdc++.h>
#define int long long
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
using namespace std;
const int N=400005, M=20;
int n, ml, mr, q, T, l[N], r[N], s[N];
int f[N][M], g[N][M], F[N][M], G[N][M];
char str[N], diff[N];
signed main() {
// freopen("1.txt","r",stdin);
freopen("tractor.in","r",stdin);
freopen("tractor.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> q, T=__lg(n);
cin >> (str+1) >> (diff+1);
up(i,1,2*n) {
if(str[i]=='L') l[++ml]=i;
if(str[i]=='R') r[++mr]=i;
}
up(i,1,n) s[i]=s[i-1]+(diff[i]=='1');
int j=n;
dn(i,n,1) {
while(r[i]<l[j]) --j;
f[i][0]=j, F[i][0]=s[j];
}
j=1;
up(i,1,n) {
while(r[j]<l[i]) ++j;
g[i][0]=j, G[i][0]=s[j-1];
}
up(j,1,T) up(i,1,n) {
f[i][j]=f[f[i][j-1]][j-1];
F[i][j]=F[i][j-1]+F[f[i][j-1]][j-1];
g[i][j]=g[g[i][j-1]][j-1];
G[i][j]=G[i][j-1]+G[g[i][j-1]][j-1];
}
while(q--) {
int l, r, p, step=1;
cin >> l >> r;
int ans=(diff[l]=='1')+(diff[r]=='1');
p=l;
dn(i,T,0) if(f[p][i]&&f[p][i]<r) step+=(1<<i), p=f[p][i];
p=l;
dn(i,T,0) if((step-1)>>i&1) ans+=F[p][i], p=f[p][i];
p=r;
dn(i,T,0) if((step-1)>>i&1) ans-=G[p][i], p=g[p][i];
cout << step << ' ' << ans << '\n';
}
return 0;
}
6-D 旅行 (travel.cpp)
见过你,上次见到你看了题解也没有补。

浙公网安备 33010602011771号