RT,训练赛复盘+题解,赛中过6题,又比理论上界少1题(
发挥比较惊险刺激,前期直接拉闸,中后期翻盘成功。
(别问我为什么又紫了,这波是两场div1各掉快100分,第二场试图跳车,不知道跳下去没有)
18:40开打,看看这惊险刺激的罚时和提交记录HHH
开始复盘吧。 (按照时间顺序来的)
J题:沙雕模拟,随便搞一搞就过去了。
G题:ghj搞的,不知道他搞了个啥,前两发数组名打错了,我偷懒没叉,过了样例就交了,一顿猛wa。
L题:也是ghj搞的,第一发是个暴力,还掉了俩CornerCase,TLE2后暴力改双指针,然后我找到一个CornerCase,ghj想起来一个,都判掉就过了。
C题:“这玩意绝壁有规律”——liangs333
然后就找规律去了,因为辣鸡div与我的辣鸡习惯,成功在找规律的途中搞掉了自己的打表程序和找出来的规律QAQ。打表程序还错了一发下标,我是ZZ。
最后wa的那两发是因为,这题要求是给你一个长度为n的数组,然后把前k个数字进行排序,然后blablabla。这踏马有
k
>
n
k>n
k>n的情况!惊不惊喜!意不意外!
出题人我祝你身体健康.jpg
经验get:找规律的时候,打个表,用打印机把表打下来就行了,不要占着电脑卡队友时间。还有要提防不良心的出题人。
E题:
“给你个二维平面,一堆忍者,每个忍者有一个clan属性和一个下标和俩坐标,每次求一段连续下标内,俩不同部落忍者的最大欧氏距离”——ghj
“这破玩意真的能做???”——liangs333
“woc这不是曼哈顿距离吗??”——liangs333
读题不规范,队友两行泪。
拿到曼哈顿下意识转 切比利夫 切比雪夫距离。
对于XY分开考虑,则变成了俩一维问题,答案是查出来取max。
上线段树,维护在一个连续区间内的坐标的最大、次大、最大所在部落、次大所在部落。
info写成struct,要写struct的merge函数,不然query要写死个人。
ghj的代码实现很妙,巧妙运用了std::pair,要我上的话估计傻了吧唧写ma,mabel之类的, 然后直接被抬走。
另外踩了个坑,注意这题的修改是增量修改,虽然单次在±1e9以内,但是增量下去就一定会炸int,所以def int ll就过去了,但是还是挨了两发罚时,就很亏。
代码是ghj写的,他负责写,我负责监工HHHH
贴个ghj的代码:
#include <bits/stdc++.h>
#define int long long
using namespace std;
struct node
{
pair<int, int> max1, max2, min1, min2;
void print()const
{
return;
printf("(%d, %d)", max1.first, max1.second);
printf("(%d, %d)", max2.first, max2.second);
printf("(%d, %d)", min2.first, min2.second);
printf("(%d, %d)\n", min1.first, min1.second);
}
} tree1[400010], tree2[400010];
node *t;
int n, m, t1[100010], t2[100010], c[100010];
int *now;
node merge(const node &a, const node &b)
{
node ans;
pair<int, int> sb[4];
sb[0] = a.max1;
sb[1] = a.max2;
sb[2] = b.max1;
sb[3] = b.max2;
sort(sb, sb + 4);
ans.max1 = sb[3];
if (sb[2].second != sb[3].second) ans.max2 = sb[2];
else if (sb[1].second != sb[3].second) ans.max2 = sb[1];
else ans.max2 = sb[0];
sb[0] = a.min1;
sb[1] = a.min2;
sb[2] = b.min1;
sb[3] = b.min2;
sort(sb, sb + 4);
ans.min1 = sb[0];
if (sb[1].second != sb[0].second) ans.min2 = sb[1];
else if (sb[2].second != sb[0].second) ans.min2 = sb[2];
else ans.min2 = sb[3];
// printf("merge()\n");
a.print();
b.print();
// printf("ans:");
ans.print();
return ans;
}
void build_tree(int x, int l, int r)
{
if (l == r)
{
t[x].max1 = make_pair(now[l], c[l]);
t[x].max2 = make_pair(-2147483648, -1);
t[x].min2 = make_pair(2147483647, -1);
t[x].min1 = make_pair(now[l], c[l]);
return;
}
int mid = (l + r) / 2;
build_tree(x * 2, l, mid);
build_tree(x * 2 + 1, mid + 1, r);
t[x] = merge(t[x * 2] , t[x * 2 + 1]);
}
//赛中一度对这个琛哥非常疑惑
void chenge(int x, int l, int r, int pos)
{
if (l == r)
{
t[x].max1 = make_pair(now[l], c[l]);
t[x].max2 = make_pair(-2147483648, -1);
t[x].min2 = make_pair(2147483647, -1);
t[x].min1 = make_pair(now[l], c[l]);
t[x].print();
return;
}
int mid = (l + r) / 2;
if (pos <= mid) chenge(x * 2, l, mid, pos);
else chenge(x * 2 + 1, mid + 1, r, pos);
t[x] = merge(t[x * 2] , t[x * 2 + 1]);
}
node query(int x, int l, int r, int L, int R)
{
if (L <= l && r <= R) return t[x];
int mid = (l + r) / 2;
if (mid < L) return query(x * 2 + 1, mid + 1, r, L, R);
if (R <= mid) return query(x * 2, l, mid, L, R);
return merge(query(x * 2, l, mid, L, mid), query(x * 2 + 1, mid + 1, r, mid + 1, R));
}
//出ans好评
long long chuans(const node &x)
{
if (x.max1.second != x.min1.second) return x.max1.first - (long long)x.min1.first;
if (x.max2.second == -1 && x.min2.second == -1) return 0;
long long tmp1 = 0, tmp2 = 0;
if (x.max2.second != -1) tmp1 = x.max2.first - (long long)x.min1.first;
if (x.min2.second != -1) tmp2 = x.max1.first - (long long)x.min2.first;
return max(tmp1, tmp2);
}
void work()
{
scanf("%lld%lld", &n, &m);
for (int i = 1; i <= n; i++)
{
int x, y;
scanf("%lld%lld%lld", &x, &y, &c[i]);
t1[i] = x + y;
t2[i] = x - y;
}
now = t1, t = tree1, build_tree(1, 1, n);
now = t2, t = tree2, build_tree(1, 1, n);
for (int type, k, x, y, i = 1; i <= m; i++)
{
scanf("%lld", &type);
if (type == 1)
{
scanf("%lld%lld%lld", &k, &x, &y);
int xx = x + y;
int yy = x - y;
t1[k] += xx;
t2[k] += yy;
now = t1, t = tree1, chenge(1, 1, n, k);
now = t2, t = tree2, chenge(1, 1, n, k);
}
else if (type == 2)
{
scanf("%lld%lld", &k, &x);
c[k] = x;
now = t1, t = tree1, chenge(1, 1, n, k);
now = t2, t = tree2, chenge(1, 1, n, k);
}
else
{
scanf("%lld%lld", &x, &y);
now = t1, t = tree1;
//好家伙fAKe
node fAKeans1 = query(1, 1, n, x, y);
now = t2, t = tree2;
node fAKeans2 = query(1, 1, n, x, y);
long long ans1 = chuans(fAKeans1);
long long ans2 = chuans(fAKeans2);
printf("%lld\n", max(ans1, ans2));
}
}
}
//经典def int ll后signed
signed main()
{
int t; scanf("%lld", &t);
for (int i = 1; i <= t; i++)
{
printf("Case #%lld:\n", i);
work();
}
return 0;
}
那么问题来了,卢姥爷在干啥。
卢姥爷在与约瑟夫问题作斗争。
经历了长达3h的闷头苦算之后,卢姥爷成功地搞定了我和ghj都假了的约瑟夫问题,代码究极短小精悍,我俩最后都没看懂他整了个啥。但是他就过去了!
“这玩意的复杂度好像是个玄学”——卢姥爷
“冲冲冲冲冲冲冲冲冲冲冲冲冲冲冲”——ghj、liangs333
另外,因为log的快速乘卡了两发,然后因为__int128导致了两次CE。
最后摸出了O(1)的快速乘就飞过去了
贴个现在也没太看明白的代码
#include <bits/stdc++.h>
#define ll int
#define int long long
#define zxc(x) cerr<<(#x)<<'='<<(x)<<'\n'
using namespace std;
inline ll Quick(ll x,ll y,ll mod)
{
return (x*y-(ll)((long double)x/mod*y)*mod+mod)%mod;
}
inline void solve(){
int n,m,k;
scanf("%lld%lld%lld",&n,&m,&k);
if(k==1) return cout<<m<<'\n',void();
int i=n-m+1;
int ans=(k-1)%i;
while(i<n&&m--){
int nxt=max
(1ll,min(n-i,(i-ans)/(k-1)));
ans=ans+Quick(nxt,k,i+nxt);
if( ans>=(i+nxt)) ans-=i+nxt;
i+=nxt;
}
cout<<ans%n+1<<'\n';
}
main(){
int T;
scanf("%lld",&T);
for(int i=1;i<=T;++i){
printf("Case #%d: ",i);
solve();
}
}
瞎扯两句总结吧。
赛前的麦当劳非常的好吃,特别是那个白嫖的鸡腿,格外的香(
依旧是究极罚时队,感觉这很危,得多加注意。
前期我一度心态很崩,队内也很闷,但是在发现其他队伍比我们还菜的时候突然就开心起来了(bushi
感觉正赛的时候我的心态可能是个问题,不管发生啥,我要稳得住才是。
后半程气氛非常好,大家也都开始整活了。整场比赛5h打满,和理论上界差的那个题是差在FWT上面,我完全不会,得靠他俩。
技能get:如果是类似于卷积形式,把+换成了xor/and/or,就顺便提一嘴是不是FWT HHHHHHH
由于这局训练赛没有太拉,周五可以不用打了!变成了三个人一块学DP,这波是恶补数位DP/DP优化/带权二分blablabla
学完萨莉亚好耶!