考试心得3

2024/9/15

link:https://www.gxyzoj.com/d/hzoj/contest/66b0925b7509073c6b14ab11/problems

考试时感觉眼睛想流眼泪,感冒还没好( 做梦一样考完了

还挺后悔的,暴力分很多,T3打了1.5小时0蛋,发现自己就不应该写二分啊

T1,暴力40分走人,不会状压dp,考完后看着wsq的代码一点一点理解了,但预处理挺奇妙的。我何时才能自己推出状压式子啊,阿布,是何时才能想出状态设定啊,没底气。。。

T2,暴力40分走人。貌似是细节题,不想改。但最后改完辣!

T3,前两道题加起来一个半小时就打完了,此题暴力却搞了甚久,始终认为它是二分,导致写得全错了。本来想挽救一下,但实在没想到真的就是无脑枚举啊!考后改了改(指改了1小时)就拿到79分的好成绩,加上map的优化(指无脑记录重复数据)即可获得99pts!!虽然这一分让我调了2个小时,但真的,双哈希也能卡过啊!!!这个题告诉我们:宁可打无脑暴力,也不能空手而归,还有,自己曾经总结的哈希区间求值是从1开始的!!!一定要看仔细!!!

T4没时间了,10分就丢了。又又又......又垫底了。T-T

2024/9/16

link:https://www.gxyzoj.com/d/hzoj/contest/66e776d4f8a2945801bcd317/problems

祝wsq生日快乐,可惜她没来

但波波买了奶茶,还是挺好的(不甜

今天挂38pts,垫底again,就是说四五十分就差了20个人左右,分差头一次真么紧。

省流:打暴力的两天。

T1,数据大水题。原题好像是dp和线段树,应该挺难的,但由于是波波的随机化数据,很简单的能被HACK的代码也能A,但自己因为手造的数据卡了两个小时,100->82,,,

T2,考场暴力数组开大TLE,20->0,正解是dfs+线段树查询,还挺简单的,自己始终卡在一个地方:(id+1)>>1不能写成(id|1)>>1,原先线段树这么写是因为乘过2后必然是偶数,加1就相当于或1,但这里的+1就不能这么写,卡了俩小时,,,,

2024/9/22

link:https://www.gxyzoj.com/d/hzoj/contest/66b0c7117509073c6b151321/problems

表示自己大部分时间都去搞T2样例了,导致T1的50分没整出来。本来T1写的16pts的 \(O(n^3)\),挺无语的,不知道为啥自己枚举完区间还要遍历一遍,考场代码改两行就50,啊。更无语的是,我加了个错误的优化,导致我原来的16pts都没有了,啊啊啊

T1是线段树,其实考场上想的错误的优化是能延伸到正解的。预处理 \(1-n\) 的mex值后,从一个区间转移到下一个区间时,如果下一个区间的mex值大于前一个区间,那么这个区间的mex值就要变小,所以要区间修改、查询、求和,用线段树,但考场上我想错了。

T2,考场上不知道推了多久才推出来样例,发现是贪心后狂写。喜提64pts,考后,把中间找到合法区间起始点的循环改成一层,开个 long long 就过了。然后又试了试,把考场交的第一版代码开个 long long 也过了,就是说你一定要相信波波的数据qwq

感觉T3还是挺抽象的,但看完Dyc的题解后好像好懂了一些,结合着luogu题解勉强看懂,挺巧妙的

2024/9/28

link:https://www.gxyzoj.com/d/hzoj/contest/66f746c1f8a2945801c53a36

改完T2精神状态极差,我考场上为什么还自信的认为我A了?

T1,考场上第一次推出dp式子!但我用在线编译发现,它好像会RE,然后就把数组开到1000,就只剩40了。考后把自己定义的dp数组拆成两个就不会RE了(本质上应该是滚动数组优化),然后就A了。

T2,大型分讨现场。考场上自信满满地打了一个半小时,一行一行地对大样例,一点一点改,加各种特判,本来觉得应该没问题了,结果0。发现大样例最后一个多数出了一个数,改后就是40了。自己再改了改,到55就上不去了。然后看dyc的代码,发现自己应该把特判的内容写到填数的过程里,写了写,到70,70 70 70 一直都是70,死活上不去了,最后 \(wme\) 学姐(太感谢她了,否则我可能到晚上都调不出来了)给我说了说,我懂了,分类讨论时 当前位如果是0 且不能删去,开头的指针应往后移一位,但加上这个还是65,显示 User output longer than standard answer. 最后发现没有判断没有删除的情况,加上终于A了,真服了(很抱歉自己写得像个流水账

2024/10/2

link:https://www.gxyzoj.com/d/hzoj/contest/66e55d2ef8a2945801ba51a6

自闭了。牙疼。想去打J。不是很想写总结。

2024/10/3

link:https://www.gxyzoj.com/d/hzoj/contest/66fd3b02f8a2945801ca8d1e

还是来写了。

T1,不会用fc,一个一个调大样例,感觉眼睛要废掉了,z[i]=0依然没有写出来,才发现n的长度为1000。

T2,60%的数据很可做,写了个记搜后一直调不出来,调了1小时,果然似了。下考后把传送门的入口和出口换了一下,就60了,发现自己用的是填表法却写成了刷表法,zz极了。

T3,Solution:

容易发现这是一个与斜率有关的题目,这种题目通常通过维护凸包,或者李超树维护
跨过\(p_i\)的区间容易转化为:以\(p_i\)为右端点的最优+以\(p_{i}+1\)为左端点的最优
两个问题同理,以右端点为例
\(sa_i=\sum_{j=1}^i a_j\)\(sb_i=\sum_{j=1}^ib_j\)
最优即\(\max_{1\leq l\leq r}\{(sa_{r}-sa_{l-1})-k(sb_{r}-sb_{l-1})\}\)
\(sa_r-k\cdot sb_{r}-\min_{0\leq l<r}\{ksb_{l}-sa_l\}\),离线之后李超树维护直线即可
时间复杂度为\(O(n\log n)\),常数略大,空间复杂度为\(O(n)\)

看不懂,去学李超树。

2024/10/4

link:https://www.gxyzoj.com/d/hzoj/contest/66ae19497509073c6b126cb8

有没有人能讲讲考试数组应该开多大啊?开小RE,开大还RE

对不起,又鸽了一天。

2024/10/6

link:https://www.gxyzoj.com/d/hzoj/contest/66ffed01f3395ed072efb1db

国庆假期没写多少总结。自愧++

现在打模拟赛很少去想正解了,每个题开题5分钟就去打暴力,非常节省时间,且性价比很高,有时候甚至打着打着暴力就想出了正解(当然这个题肯定是很水的),也很方便写对拍。

挂分:T2数组开小了,写的是 \(O(n^2)\) 的啊。

T1非常煎蛋。考虑容斥,把问题转化为 \(i∈[1,1e5],i=gcd\) 的方案数。还可以转化为 \(i∈[1,1e5],i|gcd\) ,(这并不是什么高大上的容斥,只需要减去 \((2*i)|gcd,(3*i)|gcd......(j*i)|gcd\) 即可)\(f[i][j]\) 表示第 \(i\) 行,\(j\) 的倍数有多少个,总共的方案数即为 \(∏(f[i][j]+1)-1\) 再处理一个数组倒序记录答案即可。

T2,一看数据就是状压,状态枚举,暴力加边,判断是否连通即可获得40pts,但我数组开小了,复杂度是 \(O(n^2)\) ,但我只开了10倍,20分啊啊啊。正解思路很巧妙,代码更巧妙,一个强连通分量的 出边 的 并集 所指向的 点集 肯定是不连通的,标记为不合法,最后全部状态枚举计算即可。代码放一下:

点击查看代码
cin>>n;
for(int i=1;i<=n;i++)
{
	for(int j=1;j<=n;j++)
	{
		int x;
		cin>>x;
		if(x) e[1<<i-1]|=1<<j-1;//出边
	}	
}
e[0]=(1<<n)-1;
for(int i=1;i<(1<<n);i++)
{
	e[i]=e[i^lowbit(i)]&e[lowbit(i)];//并集
}
for(int i=1;i<(1<<n);i++)
{
	if(flag[i])
	{
		for(int j=e[i];j;j=(j-1)&e[i])//枚举子集(一个很常用的方法)
		{
			flag[i|j]=false;	
		}	
	} 
}	
ans=0;
for(int i=0;i<(1<<n);i++)
{
	ans+=flag[i];	
}
cout<<ans<<endl;

T3,糖。

T4跟以前树剖里的染色几乎一模一样,维护方式都是相同的,树剖区间求和也可以参考一下。改题时这道题直接三发入魂,不到10分钟就AC了,rp神秘定律

P.S.月考寄中寄(想当年 \(dzb\) 大佬发了这句话后直接年一了,%%%),考的还没有初试J好(满分100),诚心祈祷。

疯狂颓颓颓,看游记,背图论板。

2024/10/20

link:https://www.gxyzoj.com/d/hzoj/contest/670781e8f3395ed072f56a2a/problems

又是爆炸的几天,分数永远比考场上估的低,根据我长达三个月的观察后,发现自己挂分主要集中在以下几点:

  1. 眼瞎。不用解释了,比如看错输出顺序,看错题目条件等等,解决方案:每个题读三遍,包括但不限于题面上的所有字。

  2. 数组开大/开小。比如开了个85^4的数组。解决方案:

  3. 漏判/少判边界条件。常出现在dfs或bfs中。解决方案:对自己重拳出击,认认真真检查代码,尤其是判断当前坐标加上/减去某些值的时候是否越界。

  4. 考虑不全面。其实跟上面的差不多。不全面因素主要有:计算方案数时一定要注意是否合法。

  5. 数组/变量打反。解决方案:一定要在头脑清醒的时候打代码!!!

回归正题。今天又挂了。

T1,考场上写的57pts的做法,但是炸成35,原因就是边界条件没判全。发现自己的逻辑思维和其他人很不一样,大家都是枚举这个可以反转的范围,只有我枚举的是每次向左减几或向右加几,也导致我看正解困难了许多,所以我卡常卡过了。题解思路还是很好懂的,定义一个 nxt 数组(链表),记录着每次+2时下一个到哪里,不断往后移,因为有可能重复,所以这相当于一个剪枝。

T2, 只写了3分,还因为没判0挂了。不知道考场上自己为啥不打dfs的14分,好像直接忽略了,真服了

2024/10/21

link:https://www.gxyzoj.com/d/hzoj/contest/671591769753225a002edc75/problems

又应验了上面写的眼瞎,T2没判-1。。。

T1是我考场上开的最后一道题随便打了打暴力,发现自己的搜索连 2 3 都跑不出来,直接 abandon 了。正解吧,代码是简单的,思路是奇妙的,主打这就是一个分类讨论。给的部分分还挺能启发的

T2是我开的第一道题。花了0.5h奋力打50pts的暴力(实际上是40pts),检查了好几遍代码,觉得肯定没问题了吧,啊,然后就0了。然后板有问题。

2024/10/22

link:https://www.gxyzoj.com/d/hzoj/contest/6716f1826529f6cc995c3595/problems

最抽象的一集。

T1签到题,本来要打部分分的,后来推了推发现直接排序输出就完了(瞬间找回了自信),开了个vector存储、删除,觉得写起来挺简单的。大样例对了一些就扔了不管了。觉得肯定能A吧。然后考完看排行榜,哇塞,T1怎么爆炸了啊啊啊,咋能TLE呢。然后一问发现vetor删除操作复杂度是 O(n) 的,那我用vector图啥啊。原地裂开。

T2发现只会搜,那就搜吧,写了写,过了第一个样例,第二个样例死活过不去,然后就卡着了,特殊性质随便蒙了个上去,结果显然0分。正解是本质不同子序列计数问题,bitset开个1e5*2e4的dp数组,dp[i][j]表示长度为i,末尾为j的个数。前缀和优化即可。至于%2,因为不是质数,直接判断组合数奇偶性,位运算转移。然后自己是真的啥也想不出来啊。

转移是简单的 优化是 easy

T3是我考场上最失败的一道题,我花了1.5h想暴力、打暴力,看到ABCD这么多性质肯定有会写的,6e3那就想想 O(n^2) 的暴力呗。仔细读题(第一遍读错了)发现好像没那么好写,算了先写再说,结果发现第二个样例过不去,仔细分析了一下,发现好像只会 O(n^3) 的5分暴力。又裂开了啊。然后就只剩5分了,写了100多行,啊。然后波波发的std700行代码。鉴定为不可做题。

T4因为只剩半小时多一些了,赶紧写搜,结果没调完。正解也挺抽象,想弃了。

达成成就:4天模拟赛挂176pts(奠定了s挂100的感情基调)

2024/11/24

link:https://www.gxyzoj.com/d/hzoj/contest/6741cff636620b92bbb48958

整整一个月没有打模拟赛了。

考完csp感觉整个人都不一样了,被流放到2机房了。好啊!这真的太适合我了。

T1一眼搜。但因为脑抽给dfs多加了一层循环+continue错(纯纯纸张)挂掉70pts。

T2也很一眼。但因为我dp思维定式硬要两层循环跑完dp,实际上只需简单的优化即可减掉一层,不对,其实应该是dp定义的不好。dp[i]应该是包括i这一位的前后最大值,然后两边计算取min即可。就是说自己脑子始终转不过去那道弯。*

T3其实是一眼。考场上只要我自己再去看一眼那个dfs就行了啊。还有儿子的map,考场上都想到了。可能是因为去一层次考了一个暑假导致现在无法辨别是不是煎蛋题。多考考应该就适应了。

T4并不一眼。但其实很好理解的。相当于把这一串数每隔k个分一段,然后分成两边处理。vector开个f和g数组。f[i][j]表示第i位到分界点,容量为j的最大值,g[i][j]表示分界点到i,容量为j的最大值。然后显然就有一个柿子是max(f[i][j], g[i+K-1][W-j])(枚举j为容量)表示这个区间的最大值。注意细节。

2024/12/15

link:https://www.gxyzoj.com/d/hzoj/contest/67556a5cb96062fe8cd66e7d

可以说是这么久来挂分最少的一场了。(wsq大佬太强了%%%)

由于T1一开始放的原所以临时换题导致我先从T2开的。然后T1一看是期望直接弃了(这是我整场考试最失误的一点),最后一个小时才看的T1结果50pts就打挂了。你别说,前30分拿到了T1后面就真的不难了。

首先这个题就是要想到一遍dfs如何处理出以一个点为根的情况及答案,很容易发现其实每一个点最终的总共情况数 就是以这个点为根的叶子结点数size,然而每一个 在以1为根的树中 不是叶子节点的节点 的 size 值其实就是 size[1],叶子节点的即为 size[1]-1,所以我们的目标就变为求每一个点的所有情况和,因为一遍dfs就可以求出根节点1的相关答案,所以就是一个简单的换根了。这个换根dp需要注意的一点就是要将叶节点和非叶节点分开讨论,因为毕竟以他们为根的叶节点数不同么。

浅浅的放一下转移吧:
void dfs1(int u,int fa)
{
	for(int i=head[u];i;i=edge[i].next)
	{
		int v=edge[i].to;
		if(v==fa) continue;
		if(f[v])
		{
			dp[v]=dp[u]+(size[rt]-2)*a[v]-a[u]; 
		} 
		else
		{
			dp[v]=dp[u]+(size[rt]-size[v])*a[v]-size[v]*a[u];
		}
		dfs1(v, u);
	}
}

T2吧,看出了trie树上建反串并找出了dp转移的两种状态。但是我的dp只能使最后的序列单调上升,按理来说这个样子也是可以的:
,所以自己就没有考虑到这种情况,挂的比较惨烈。
大致就是dp维护当前点到叶节点的最长距离,然后答案就是最长距离+次长距离+儿子数-2取max即可。

T3,我他妈看了3个天才看懂,因为每次就是不理解题解里说的一段话,最后终于懂了,豁然开朗了,但没时间改了,浪费了好多时间啊啊啊

T4 呵呵呵,我花了几个晚上,写了6个dfs(其实也可以并到一起写的)然后不停地hack+调过了,因为这个题其实就是一个分类讨论,只有三种情况:
然后根据这些图推推答案,dfs处理即可。

2024/12/29

link:https://www.gxyzoj.com/d/hzoj/contest/6767deb900191f7b828fb17e/problems

状压dp专题我就刷了4道(还有两道不是状压),可以说是没啥长进,然后硬着头皮打得模拟赛。

T1当时写了个dijkstra跑最长路,其实dp啥的我都写好了,转移方程也没啥问题,但dp状态设计时我少了一维:当前节点。挺搞笑的,但也深刻体现出我dp经验还是太少了,考场上发现这个转移会有重复的急死了,下考后瞬间醒了。还有一点是转移的时候应该注意当前合不合法(是不是从0开始的),也没啥难度啊,但就是有些细节没想到啊。

T2也不难啊,很像以前的状压板题,但自己根本没有往正解想,直接写了暴力,dp[i][j][k]表示当前第i行,状态为j,第i-1行状态为k,转移时显然再枚举下i-2行的状态,加上代价取min即可,个数跟着一块转移就好了。注意判断是否合法这样写:(j|k|l|(k<<1)|(k>>1))&tot==tot(j k l分别是i i-1 i-2行的状态,tot为 (1<<m)-1)。

T3已经快不记得什么了,三维的状压,dp[x][y][t][s]表示在t时刻,当前在 (x,y) 这一坐标,搬走的西瓜状态为 s 的最少移动次数。mp数组辅助转移,mp[x][y][s]表示在t时刻,当前在 (x,y) 这一坐标的西瓜状态。

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=105;
int h, w, T, sx, sy, n, m, mp[10][10][maxn], dp[6][6][maxn][(1<<10)+5], idx;
int dx[5]={0, 0, 0, 1, -1}, dy[5]={0, 1, -1, 0, 0}, ans=-1;
struct node{
	pair<int,int> id;
	int tim, s, val;
	bool operator<(const node &x) const
	{
		return x.val<val;
	}
};
signed main()
{
	cin>>h>>w>>T>>sx>>sy;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		int t1, t2, opt;
		cin>>t1>>t2;
		cin>>opt;
		int tmp;
		if(opt==0) tmp=-1;
		else tmp=1<<idx, idx++;
		for(int j=t1;j<t2;j++)
		{
			int x, y;
			cin>>x>>y;
			mp[x][y][j]|=tmp;
		}	
	}
	if(!~mp[sx][sy][1]) 
	{
		cout<<-1;
		return 0;
	}
	memset(dp, -1, sizeof(dp));
	dp[sx][sy][1][mp[sx][sy][1]]=0;
	priority_queue<node> q;
	q.push(node{make_pair(sx, sy), 1, mp[sx][sy][1], 0});
	while(q.size())
	{
		int x=q.top().id.first, y=q.top().id.second, tim=q.top().tim, s=q.top().s;
		q.pop();
		if(tim==T)
		{
			if(s==(1<<m)-1) 
			{
				ans=dp[x][y][tim][s];
				break;
			}
			continue;
		}
		for(int i=0;i<5;i++)
		{
			int tx=x+dx[i], ty=y+dy[i];
			int ss=s|mp[tx][ty][tim+1];
			if(tx==0||tx>h||ty==0||ty>w||!~mp[tx][ty][tim+1]||~dp[tx][ty][tim+1][ss]) continue;
			dp[tx][ty][tim+1][ss]=dp[x][y][tim][s]+(abs(dx[i])|abs(dy[i]));
			q.push(node{make_pair(tx, ty), tim+1, ss, dp[tx][ty][tim+1][ss]});
		}
	}
	cout<<ans;
	return 0;
}

2025/2/11

link:https://www.gxyzoj.com/d/hzoj/contest/6719a7a74c46f9e25f7b1d4b/problems

今天幸运了一波,不知道为啥大家T1都挂了好多,然后没有垫底,感觉T1想想线段树方面的优化就可以做出来了(前提是各种细节没有打挂),T2看样子也只会30pts的暴力分,T3不会代码实现,T4爆搜加点优化应该是能拿到24pts/36pts的。

T1显然O(n^2)做法非常简单,就是变种LIS,\(b[i]=1\)的分也很好拿,加个贪心+二分即可,妥妥的LIS板子啊。官方题解写的就很不一样,设 \(dp[i][j]\) 表示前 \(i\) 个数选了长度为 \(j\) 的最后一个数的最小值,当 \(a[i]>b[j-1]*dp[i-1][j-1]\) 时,\(dp[i][j]=min(dp[i-1][j], a[i])\).滚动数组可以滚掉一维。

T2数论题,但这个题技巧性不是很多,就是推推狮子,找找规律,计算的时候分类讨论清楚就行了。但让我再做一遍我可能还是不会

T4爆搜题。

2025/3/22

link:https://www.gxyzoj.com/d/hzoj/contest/67ddf93175a0c6c1d711d98d/problems

改不动T4于是来写总结了

时隔一个月考试,嗯,其实跟暑假模拟赛状态一样。

T1,不太记得一开始咋想的了,在草稿纸上写了一整张的式子(不是为啥我要把同样的式子写这么多遍?)然后感觉是大家都可以切的而我只能拿70pts的题,发现离正解唯一的困难就是不会处理整除,但不会就是不会,于是直接消元解方程(整除去分母了),和样例就差1,和暴力拼了拼居然拿到91pts?!还是数据过于水了。题解是二分,恍然大悟了,其实题解的做法应该是二分+枚举三个数,因为可以根据答案和对角线的值算出另两个格子的大致范围,然后用 for 循环在估计值的附近枚举即可,复杂度是可以过的。

T2,本来觉得肯定是树形dp吧,居然是不是很难的计数题。一个 trick 就是二进制拆分,按位算贡献。对于一个点u,它的直接子节点中的第m位为1的个数记为sum,则方案数为 \(2^{sum-1}\) (挑奇数的),然后再减掉u点只有一只蚂蚁的情况。注意根节点要单独处理。其实是非常简单的。题解

T3,也是不难的题,主要就是一种贪心策略来想。题解

T4,分块即可。题解是线段树上维护分段函数,代码不是很长,但由于种种原因并不是很懂,于是就不说了。

2025/3/29

link:https://www.gxyzoj.com/d/hzoj/contest/649ce6c050c8246d4569a92c/problems

看似8个人在考试,实则54人。垫底拿下!

省流:原。

T1死磕了1h发现假了(想的是单独记录每一位的贡献),很慌于是先做了T2。因为T2是原题而且还记得是贪心,于是疯狂手模找贪心策略,成功敲出了那一场的64pts,O(n^2)的做法,但数据挺水的据说可以过?但我WA了。10分钟速通T3的 O(n^2) 50pts的暴力(T3也是原)就立马去看T4了,发现很不可做又回去看T1,换了个思路瞬间通畅了,写了O(n^2)的dp(加了一点小优化拿到了72pts!)就开始摆烂了。

T1其实只需要把判断条件换一下位置即可:


有个小小的问题就是不能取相等的a[i],可以在排序时特判一下相等时按i-a[i]从大到小排,那么就只能取其中的任意一个了,有效地避免了麻烦。

T2一个大胆猜想:断环为链后必有一个分割点,使得按照顺时针顺序原来在它之前的点上的钱一定不会运到在它之后的点上。这是最优方案。
Q:这个点怎么选呢?
A:从它开始移动一定不会出现钱不够的情况,即 \(c[i]-1\) 的前缀和一定不为负数,即为最大子段和起点。
Q:怎么移动是最优的呢?
A:根据 \((x+y)^2>=x^2+y^2\) ,考虑尽量让距离变“碎”,在从前往后遍历时,用队列把每个点的钱取出,再把队首的钱移到当前点上。
Q:代码怎么实现呢?

A:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1e5+5;
int n, c[maxn*2], lst[maxn], res, pos, vis[maxn];
queue<int> q;
signed main()
{
	freopen("barn.in","r",stdin);
	freopen("barn.out","w",stdout);
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>c[i];
		c[i+n]=c[i];
	}
	for(int i=1;i<=n;i++)
	{
		int sum=0, flag=0;
		for(int j=i;j<=i+n-1;j++)
		{
			sum+=c[j]-1;
			if(sum<0)
			{
				flag=1;
				break;
			}
		}
		if(flag==0) 
		{
			pos=i;
			break;
		}
	}
	for(int i=pos;i<=pos+n-1;i++)
	{
		while(c[i]--) q.push(i);
		res+=abs(i-q.front())*(i-q.front());
		q.pop();
	}
	cout<<res;
	return 0;
}
/*
10
1
0
0
2
0
0
1
2
2
2
 
33
*/

T3,又一道原题。50pts很简单。考虑用线段树维护每个左端点 \([i,n]\) 的mex值。具体地,先求出左端点为1的和,那么现在就要处理减掉第一位的mex和。记 \(lst[i]\) 表示i以后第一个值为 \(a[i]\) 的下标,那么修改的就是 \([i+1,lst[i]-1]\) 这个区间的 大于 \(a[i]\) 的mex值为 \(a[i]\) 。题解里是用二分找到大于 \(a[i]\) 区间的,实际上还可以维护一个区间最大值来找,码量都差不多。

T4,也不是很难的题。考虑dp,设 \(dp[i][j][k]\) 表示从i开始,走k步到达j的方案数,那么\(dp[i][j][k]=dp[i][l][k-1]*dp[l][j][1]\) ,答案即为 \(dp[i][i][1~k]\) 的和。观察这个转移方程很像矩阵快速幂可以优化的,于是————

设A[i][j]=1 表示 i,j 之间有有向边。
设 B 矩阵中仅 \(B[i][i]=1\),其他为 0(单位矩阵)。
\(B * A^x = C\),则 C[i][j]表示 i 到 j 长度恰为 x 的路径数。
\(B*A,B*A^2,B * A ^ 3 …… B * A ^ {(k-1)}\)的主对角线的值(\(C[i][i]\),即自环)累计即为答案。
相当于 \(D=B * (A + A^2 + A^3 … A^(k-1))\),求 D 的主对角线(\(D[i][i]\))的和。
而求解 \(A + A^2 + A^3 … A^(k-1)\),类似于求解等比数列。
根据 K 的奇偶有,
如果 k 为偶数,那么
\((A+A^2+....A^K) = (A+...+A^{K/2})+A^{K/2}*(A+...+A^{K/2})\)
如果 k 为奇数,那么
\((A+A^2+....A^K) = (A+...+A^{K/2})+A^{K/2}*(A+...+A^{K/2})+A^k\)
但我认为这个题的重点不在于这里,而是递归的优化。常规思路就是把上面的式子打一遍,但只能得60pts。原因是递归里面套了快速幂,考虑将快速幂一层一层的乘上来,特判奇数的情况就可以了。

点击查看代码
inline pair<node,node> dfs(node a,int k)
{
	if(k==1) return make_pair(a, a);
	pair<node,node> res=dfs(a, k/2);
	res.first=add(res.first, mul(res.first, res.second));
	res.second=mul(res.second, res.second);
	if(k%2)
	{
		res.second=mul(res.second, a);
		res.first=add(res.first, res.second);
	}
	return res;
}

2025/4/5

link:https://www.gxyzoj.com/d/hzoj/contest/67ee422ee240365cb02fe742/problems

改完T4心情大好于是来写总结。

T1没有想到容斥于是开始打表,就是算每一个可能的数字的个数的和。手动计算1e16大小的数据,结果和大阳历差4!!!难绷啊,然后最终拿了60pts,发现打表少打了一个成功挂掉40pts。讲题时blm的做法居然和我一样,很惊喜啊。正解通过容斥算出每个答案对应的个数即可。

T2也不难。考场上写了50pts(其实没写挂是能拿到90pts的!!)然后挂成60,最基本的3个点挂了。很无脑的一个一个修改再查询最大值再修改...我的想法和正解仅仅差一个 \(i*(k-i)*p\) (其中i表示横着修改几行),其他性质全想到了。代码实现也很简单,就是预处理出最大值然后枚举i即可。

T3先放一下。

2025/4/20

link:https://www.gxyzoj.com/d/hzoj/contest/680441570c51e01c11b5d2db/problems

不出意外地也是垫底了。

T1,其实我连O(nb)的做法都没有想出来以为是和以前一样的清新数论题,然后不会。首先枚举答案我就没想到,枚举答案后就可以轻松地判断那两个倍数是否在两个区间里了。现在复杂度是 \(O(nb)\) ,考虑优化。会发现对于一个b,可能有很多连续的答案(称为i)满足b/i的值是相同的,例如b=15,i=8、9、10、11、12、13、14、15,我们需要的只是那个最大的,发现这个最大的答案就是 b/(b/i),复杂度降为 \(O(n \sqrt b)\),这个好像叫做整除分块。

T2也是挺神人的题,发现其他人似乎都想到矩阵快速幂了,慌。设 \(dis[i][j]\) 表示

2025/5/4

有点崩溃。。。T2当时去博客粘了杨辉三角板子,后果就是忘打模数T2挂了50,教训是完善博客不要粘板子(我努力吧)。T1用的dijkstra导致写得特别复杂,最长路一定是拓扑排序+dp!!!。T4数组开小又没有看出显然得过分的性质,挂惨了。

T1,学习了可删除堆。先求出以每个点为起点的最长路dis[i],再求出以每个点为终点的最长路dit[i](建反向边),神奇的将这些点想象成两部分:建议直接去看题解理解,用可删除堆存储最长路求出答案即可。

T2,神奇数论题。注意到\(95041567=31\times37\times41\times43\times47\),相当于把这个模数分成5个质数,算出与 \(bell[n]\) 同余的5个数,最后用CRT合并即可。至于如何计算,考虑用矩阵快速幂,对n<50的Bell数进行预处理,构造一个p*p(p为31,37...47)的矩阵:
设 t=n/(p-1),k=n%(p-1),利用 \(B_n=A^tBk\),计算时只需求第一个元素即可。

T3,考试时难得想出来点dp了然而十分不好拿50分。正解是AC自动机dp,设 \(dp[i][j][k][l]\) 表示总共走了i步,有j个 R ,当前在AC自动机的k节点,两个串的匹配度为l(0全没有匹配,1/2匹配了对应的那个串,3都匹配上了)。比较常规的dp吧,感觉是这几道题里最简单的。

T4,很仙啊

2025/5/17

link:https://www.gxyzoj.com/d/hzoj/contest/6821bd14ed58fbbad04359b7/problems

嗯,稳住心态,慢慢改。

下面的话是给自己说的

T1挂了不是你的错,只是你忘了dijkstra的复杂度;T2挂了不是你的错,只是你忘了a1a2是百分数;T3没写不是你的错,只是你没有读懂题目。T4只写了暴搜不是你的错,因为大家也都只写了搜。

纯属发癫了

T1当时一眼图论,然后想的就是建图跑最短路(当然时间复杂度严重爆表),有那么一瞬间觉得有点像分层图,想到了点到门,门到门,门到点的思路,但还是弃了。40%的dp很好想,比较巧妙的就是最后线段树的优化。具体的,线段树上每个节点维护一个区间 [l,r],里面储存第 l 层的每个门到第 r 层每个门的最短路。先把同层的门之间的距离预处理出来,那么就只剩合并了。合并和线段树维护最大子段和有点像,只要确保门没有对错门即可。

点击查看代码
//dijkstra复杂度O((n+m)logm) 要记住啊!!! 
//其实考场上有想到点到门,门到门,门到点的思路,但觉得是图论,就没往下想了 
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1e5+5;
int n, m, dp[maxn][2];//0上1右 
struct node{
	int x, y;
}a[maxn][2];
int dist(int a,int b,int c,int d)
{
	return abs(a-c)+abs(b-d);
}
struct mat{
	int f[2][2];
}b[maxn];
mat merge(mat a,mat b)
{
	mat t;
	t.f[0][0]=min(a.f[0][0]+b.f[0][0], a.f[0][1]+b.f[1][0]);
	t.f[0][1]=min(a.f[0][0]+b.f[0][1], a.f[0][1]+b.f[1][1]);
	t.f[1][0]=min(a.f[1][0]+b.f[0][0], a.f[1][1]+b.f[1][0]);
	t.f[1][1]=min(a.f[1][1]+b.f[1][1], a.f[1][0]+b.f[0][1]);
	return t;
}
#define lid id<<1
#define rid id<<1|1
struct seg_tree{
	mat t;
	int l, r;
}tr[maxn<<2];
void pushup(int id)
{
	tr[id].t=merge(tr[lid].t, tr[rid].t);
} 
void build(int id,int l,int r)
{
	tr[id].l=l, tr[id].r=r;
	if(l==r) 
	{
		tr[id].t=b[l];
		return ;
	}
	int mid=(l+r)>>1;
	build(lid, l, mid);
	build(rid, mid+1, r);
	pushup(id);
}
mat query(int id,int l,int r)
{
	if(l<=tr[id].l&&r>=tr[id].r) return tr[id].t;
	int mid=(tr[id].l+tr[id].r)>>1;
	if(r<=mid) return query(lid, l, r);
	else if(l>mid) return query(rid, l, r);
	else return merge(query(lid, l, mid), query(rid, mid+1, r));
}
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	cin>>n;
	for(int i=1;i<n;i++)
	{
		int x, y, xx, yy;
		cin>>x>>y>>xx>>yy;
		a[i][0].x=x, a[i][0].y=y;
		a[i][1].x=xx, a[i][1].y=yy;
	}
	for(int i=1;i<n;i++)//预处理同层的 
	{
		b[i].f[0][0]=dist(a[i][0].x+1, a[i][0].y, a[i+1][0].x, a[i+1][0].y)+1;
		b[i].f[0][1]=dist(a[i][0].x+1, a[i][0].y, a[i+1][1].x, a[i+1][1].y)+1;
		b[i].f[1][0]=dist(a[i][1].x, a[i][1].y+1, a[i+1][0].x, a[i+1][0].y)+1;
		b[i].f[1][1]=dist(a[i][1].x, a[i][1].y+1, a[i+1][1].x, a[i+1][1].y)+1;
	}
	build(1, 1, n-1);
	cin>>m;
	while(m--)
	{
		int x, y, xx, yy;
		cin>>x>>y>>xx>>yy;
		int t1=max(x, y), t2=max(xx, yy);
		if(t1>t2) swap(x, xx), swap(y, yy), swap(t1, t2);
		if(t1==t2)
		{
			cout<<dist(x, y, xx, yy)<<"\n";
			continue;
		}
		mat res;
		res.f[0][0]=dist(x, y, a[t1][0].x, a[t1][0].y);
		res.f[0][1]=dist(x, y, a[t1][1].x, a[t1][1].y);
		if(t2-t1>1) res=merge(res, query(1, t1, t2-2));
		int ans=min(res.f[0][0]+dist(xx, yy, a[t2-1][0].x+1, a[t2-1][0].y), res.f[0][1]+dist(xx, yy, a[t2-1][1].x, a[t2-1][1].y+1));
		cout<<ans+1<<"\n";
	}
	return 0;
} 

T2当时就常规的把每条光线的式子写出来,然后推狮子。不知道我当时咋想的,乘a1 a2时忘了她们是百分数,但是全忘了时百分数其实也能推出正确的式子。关键是后面我除以b1 b2时又想起他们时百分数了。很抽象,

T3的dp其实不难写。但考场上我没有读懂题,也看不懂样例解释,因为题目省略了“加入队列”这一过程,无语啊。设dp[i][j]表示长度为i的,最后一个数字为j的队列的方案数,只需枚举它前一个数即可。最后拿前缀和优化,但是我想到了一种用树状数组优化的方法,即交替修改,求和。过了也只能说数据太水了吧。。。

2025/6/2

link:https://www.gxyzoj.com/d/hzoj/contest/6839b474614f19035b849106


飞扬的少年最动人心,奔跑的时候像是穿过了光阴。

posted @ 2024-10-04 14:39  zhouyiran2011  阅读(142)  评论(0)    收藏  举报