暑假集训CSP提高模拟23

暑假集训CSP提高模拟23

组题人: @KafuuChinocpp | @H_Kaguya

\(T1\) P221. 进击的巨人 \(5pts\)

  • 原题: 2024牛客暑期多校训练营4 J Zero

  • 部分分

  • 正解

    • 观察到 0 会把区间分成若干个部分,这若干个部分之间互不影响。设 \(cnt_{i}\) 表示 \([1,i]\)? 的个数。假设我们我们当前枚举的部分为 \([L,R]\) ,其中仅包含 1? 。其对答案的贡献为 \(\begin{aligned} &\sum\limits_{l=L}^{R}\sum\limits_{r=l}^{R}(r-l+1)^{k} \frac{1}{2^{cnt_{r}-cnt_{l-1}}} \\ &=\sum\limits_{l=L}^{R}\sum\limits_{r=l}^{R}\sum\limits_{i=0}^{k}\dbinom{k}{i}r^{k-i}(-l+1)^{i} \frac{1}{2^{cnt_{r}-cnt_{l-1}}} \\ &=\sum\limits_{i=0}^{k}\dbinom{k}{i}\sum\limits_{l=L}^{R}\sum\limits_{r=l}^{R}r^{k-i}(-l+1)^{i} \frac{2^{cnt_{l-1}}}{2^{cnt_{r}}} \\ &=\sum\limits_{i=0}^{k}\dbinom{k}{i}\sum\limits_{r=L}^{R} \frac{r^{k-i}}{2^{cnt_{r}}}\sum\limits_{l=L}^{r}(-l+1)^{i} 2^{cnt_{l-1}} \end{aligned}\) 。枚举 \(i\) ,前缀和维护后半部分即可。

      点击查看代码
      const ll p=998244353;
      char s[100010];
      ll cnt[100010];
      ll qpow(ll a,ll b,ll p)
      {
      	ll ans=1;
      	while(b)
      	{
      		if(b&1)
      		{
      			ans=ans*a%p;
      		}
      		b>>=1;
      		a=a*a%p;
      	}
      	return ans;
      }
      ll C(ll n,ll m,ll p)
      {
      	if(n>=m&&n>=0&&m>=0)
      	{
      		ll up=1,down=1;
      		for(ll i=n-m+1;i<=n;i++)
      		{
      			up=up*i%p;
      		}
      		for(ll i=1;i<=m;i++)
      		{
      			down=down*i%p;
      		}
      		return up*qpow(down,p-2,p)%p;
      	}
      	else
      	{
      		return 0;
      	}
      }
      ll ask(ll l,ll r,ll k)
      {
      	ll sum,ans=0;
      	for(ll i=0;i<=k;i++)
      	{
      		sum=0;
      		for(ll j=l;j<=r;j++)
      		{
      			sum=(sum+qpow(-j+1,i,p)*qpow(2,cnt[j-1]-cnt[l-1],p)%p+p)%p;
      			ans=(ans+((C(k,i,p)*qpow(j,k-i,p))%p*qpow(qpow(2,cnt[j]-cnt[l-1],p),p-2,p)%p)*sum%p)%p;
      		}
      	}
      	return ans;
      }
      int main()
      {
      	freopen("attack.in","r",stdin);
      	freopen("attack.out","w",stdout);
      	ll n,k,ans=0,i,l,r;
      	cin>>n>>k>>(s+1);
      	for(i=1;i<=n;i++)
      	{
      		cnt[i]=cnt[i-1]+(s[i]=='?');
      	}
      	for(l=r=1;l<=n;l++)
      	{
      		if(s[l]!='0')
      		{
      			r=l;
      			while(r<=n&&s[r]!='0')
      			{
      				r++;
      			}
      			r--;
      			ans=(ans+ask(l,r,k))%p;
      			l=r;
      		}
      	}
      	cout<<ans<<endl;
      	fclose(stdin);
      	fclose(stdout);
      	return 0;
      }
      
    • @hh弟中弟 还有类似 luogu P1654 OSU! 维护幂次对答案贡献的做法,详见 站外题求助

\(T2\) P226. Wallpaper Collection \(35pts\)

  • 原题: 2024牛客暑期多校训练营6 I Intersecting Intervals

  • 感觉状态设计和优化很逆天,将官方题解改了改。

  • 部分分

    • \(20 \sim 30pts\)
      • \(f_{i,l,r}\) 表示第 \(i\) 行选择的区间为 \([l,r]\) 时最大的喜爱值之和,状态转移方程为 \(f_{i,l,r}=\max\limits_{\max(l,L) \le \min(r,R)}\{ f_{i-1,L,R} \}+\sum\limits_{j=l}^{r}a_{i,j}\)

      • 时间复杂度为 \(O(nm^{4})\)

        点击查看代码
        ll a[1010][1010],sum[1010][1010],f[2][1010][1010];
        int main()
        {
        	freopen("WallpaperCollection.in","r",stdin);
        	freopen("WallpaperCollection.out","w",stdout);
        	ll n,m,ans=-0x7f7f7f7f7f7f7f7f,maxx,i,j,k,l,r;
        	scanf("%lld%lld",&n,&m);
        	for(i=1;i<=n;i++)
        	{
        		for(j=1;j<=m;j++)
        		{
        			scanf("%lld",&a[i][j]);
        			sum[i][j]=sum[i][j-1]+a[i][j];
        		}
        	}
        	memset(f,-0x3f,sizeof(f));
        	for(i=1;i<=m;i++)
        	{
        		for(j=i;j<=m;j++)
        		{
        			f[0][i][j]=0;
        		}
        	}
        	for(i=1;i<=n;i++)
        	{
        		for(j=1;j<=m;j++)
        		{
        			for(k=j;k<=m;k++)
        			{
        				maxx=-0x7f7f7f7f7f7f7f7f;
        				for(l=1;l<=j-1;l++)
        				{
        					for(r=j;r<=m;r++)
        					{
        						maxx=max(maxx,f[(i-1)&1][l][r]+sum[i][k]-sum[i][j-1]);
        					}
        				}
        				for(l=j;l<=k;l++)
        				{
        					for(r=l;r<=m;r++)
        					{
        						maxx=max(maxx,f[(i-1)&1][l][r]+sum[i][k]-sum[i][j-1]);
        					}
        				}
        				f[i&1][j][k]=maxx;
        			}
        		}
        	}
        	for(i=1;i<=m;i++)
        	{
        		for(j=i;j<=m;j++)
        		{
        			ans=max(ans,f[n&1][i][j]);
        		}
        	}
        	printf("%lld\n",ans);
        	fclose(stdin);
        	fclose(stdout);
        	return 0;
        }
        
    • \(40pts\)
      • \(\max(l,L) \le \min(r,R)\) 等价于 \([L,R]\)\([l,r]\) 有交,即存在一个 \(j \in [l,r]\) 使得 \([L,R]\) 包含 \(j\) 。不妨钦定 \(j\) 然后进行转移。
      • 具体地,预处理 \(g_{i,j}=\max\limits_{l \le j \le r} \{ f_{i,l,r} \}\) ,则 \(f_{i,l,r}=\max\limits_{j=l}^{r}\{ g_{i-1,j} \}+\sum\limits_{j=l}^{r}a_{i,j}\)
      • 时间复杂度为 \(O(nm^{3})\)
    • \(60pts\)
      • 区间有交等价于相邻两行均满足四连通,考虑优化状态设计。
      • \(f_{i,j}\) 表示第 \(i\) 行起始位置/钦定选择位置为 \(j\) 时的最大的喜爱值之和。设 \(i-1\) 行起始位置/钦定选择位置为 \(k\) ,则 \(i\) 行所选择的区间 \([L,R]\) 一定满足 \(\begin{cases} L \le \min(j,k) \\ \max(j,k) \le R \end{cases}\) ,此时转移为 \(f_{i,j}=\max\limits_{k=1}^{m} \{f_{i-1,k}+\max\limits_{L \le \min(j,k) \land \max(j,k) \le R}\{ \sum\limits_{h=L}^{R}a_{i,h} \} \}\)
        • 官方题解上这里是有转化题意铺垫的 ,挂一下转化题面,但感觉还是不如钦定选择一个元素好理解。
          • 转化题意
          • 想象主人公面前有一个 \(n + 2\)\(m\) 列的矩阵,从第 \(0\) 行一个位置开始,他有如下几种操作:
            • 向左移动一个单位,并收集所到达位置上的壁纸。
            • 向右移动一个单位,并收集所到达位置上的壁纸。
            • 向下移动一个单位,并收集所到达位置上的壁纸。
          • 其中第 \(0\) 行和第 \(n + 1\) 行没有壁纸,一个壁纸不能被收集多次,到达第 \(n + 1\) 行时收集结束。
          • 最大化收集的壁纸的喜爱值之和。
      • \(\max\limits_{L \le \min(j,k) \land \max(j,k) \le R}\{ \sum\limits_{h=L}^{R}a_{i,h} \}\) 拆开后线段树就可以维护最大前/后缀和做了,但先不要着急,式子还能再拆。
      • \(s_{i,j}=\sum\limits_{k=1}^{j}a_{i,k},t_{i,j}=\sum\limits_{k=j}^{m}a_{i,k}\) ,那么 \(\sum\limits_{h=L}^{R}a_{i,h}=s_{i,m}-s_{i,L-1}-t_{i,R+1}\) 。负号放到 \(\max\) 里面维护前后缀 \(\min\) 即可。
      • 时间复杂度为 \(O(nm^{2})\)
  • 正解

    • \(j,k\) 大小关系进行分讨。
    • 假设 \(k \le j\) ,则有 \(f_{i,j}=\max\limits_{k=1}^{j}\{ f_{i-1,k}+s_{i,m}-\min\limits_{h=1}^{k-1}\{ s_{i,h} \}-\min\limits_{h=j+1}^{m}\{ t_{i,h} \} \}\)
    • 再做一次前后缀 \(\min\) 维护即可。
    • 时间复杂度为 \(O(nm)\)
    点击查看代码
    ll a[1010][1010],f[1010][1010],s[1010][1010],t[1010][1010],mins[1010][1010],mint[1010][1010],g[1010],h[1010];
    int main()
    {
    	freopen("WallpaperCollection.in","r",stdin);
    	freopen("WallpaperCollection.out","w",stdout);
    	ll n,m,ans=-0x7f7f7f7f7f7f7f7f,i,j;
    	cin>>n>>m;
    	for(i=1;i<=n;i++)
    	{
    		for(j=1;j<=m;j++)
    		{
    			cin>>a[i][j];
    		}
    	}
    	for(i=1;i<=n;i++)
    	{
    		g[0]=-0x7f7f7f7f7f7f7f7f;
    		for(j=1;j<=m;j++)
    		{
    			g[j]=max(g[j-1],f[i-1][j]-mins[i][j-1]);
    			s[i][j]=s[i][j-1]+a[i][j];
    			mins[i][j]=min(mins[i][j-1],s[i][j]);
    		}
    		h[m+1]=-0x7f7f7f7f7f7f7f7f;
    		for(j=m;j>=1;j--)
    		{
    			h[j]=max(h[j+1],f[i-1][j]-mint[i][j+1]);
    			t[i][j]=t[i][j+1]+a[i][j];
    			mint[i][j]=min(mint[i][j+1],t[i][j]);
    		}
    		for(j=1;j<=m;j++)
    		{
    			f[i][j]=-0x7f7f7f7f7f7f7f7f;
    		}
    		for(j=1;j<=m;j++)
    		{
    			f[i][j]=max(f[i][j],h[j]+s[i][m]-mins[i][j-1]);
    		}
    		for(j=m;j>=1;j--)
    		{
    			f[i][j]=max(f[i][j],g[j]+s[i][m]-mint[i][j+1]);
    		}
    	}
    	for(i=1;i<=m;i++)
    	{
    		ans=max(ans,f[n][i]);
    	}
    	cout<<ans<<endl;
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    

\(T3\) P232. 樱花庄的宠物女孩 \(50pts\)

  • 原题: 2024牛客暑期多校训练营4 B Pull the Box

  • 部分分

    • 随机 \(pts\) :乱搞。

  • 正解

    • 人显然需要先走到一个与箱子相邻的节点 \(y\) 然后开始拉着箱子跑。
    • 因为边权只有 \(1\) ,故可以 \(BFS\) 处理出 \(x\) 在不经过 \(1\) 的情况下到与 \(1\) 相连的节点的最短路长度 \(dis\)
    • 容易用 \((u,v,k)\) 来表示箱子在 \(u\) 且人在 \(v\) 时到达该状态的最小步数 \(k\) ,合法状态的数量级为 \(O(m)\) 。初始状态为 \((1,y,dis_{y})\) ,其中 \((1,y) \in E\)
    • 然后考虑对边(将边的编号加入队列)进行 \(BFS\) 。具体地,取出队首状态 \((u,v,k)\) ,枚举所有与 \(v\) 相连的点进行转移。另外 \(v\) 被访问过两边后就不会再产生更新(说明有环),及时停止来保证复杂度。同时队列中应保证更新过程中 \(k\) 是单调递增的,在加入 \(y\) 的过程中可以双指针或用堆来维护。
    • 最后枚举与 \(n\) 相连的边进行判断即可。
    点击查看代码
    struct node
    {
    	int nxt,from,to;
    }e[2000010];
    int head[2000010],dis[2000010],vis[2000010],cnt=1;
    vector<pair<int,int> >pt;
    void add(int u,int v)
    {
    	cnt++;
    	e[cnt].nxt=head[u];
    	e[cnt].from=u;
    	e[cnt].to=v;
    	head[u]=cnt;
    }
    void bfs1(int s)
    {
    	memset(dis,0x3f,sizeof(dis));
    	queue<int>q;
    	dis[s]=0;
    	q.push(s);
    	while(q.empty()==0)
    	{
    		int x=q.front();
    		q.pop();
    		for(int i=head[x];i!=0;i=e[i].nxt)
    		{
    			if(e[i].to==1)
    			{
    				pt.push_back(make_pair(i^1,dis[x]));
    			}
    			else
    			{
    				if(dis[e[i].to]==0x3f3f3f3f)
    				{
    					dis[e[i].to]=dis[x]+1;
    					q.push(e[i].to);
    				}
    			}
    		}
    	}
    }
    void bfs2()
    {
    	memset(dis,0x3f,sizeof(dis));
    	memset(vis,0,sizeof(vis));
    	queue<int>q;
    	for(int i=0;i<pt.size();i++)
    	{
    		dis[pt[i].first]=pt[i].second;
    	}
    	int k=0;
    	while(q.empty()==0||k<pt.size())
    	{
    		if(q.size()==0)
    		{
    			if(k<pt.size())
    			{
    				q.push(pt[k].first);
    				k++;
    			}
    		}
    		else
    		{
    			int x=q.front();
    			q.pop();
    			if(vis[e[x].to]<=1)
    			{
    				vis[e[x].to]++;
    				while(k<pt.size()&&pt[k].second==dis[x])
    				{
    					q.push(pt[k].first);
    					k++;
    				}
    				for(int i=head[e[x].to];i!=0;i=e[i].nxt)
    				{
    					if(e[i].to!=e[x].from)
    					{
    						if(dis[i]>dis[x]+1)
    						{
    							dis[i]=dis[x]+1;
    							q.push(i);
    						}
    					}
    				}
    			}
    		}
    	}
    }
    int main()
    {
    	freopen("Sakura.in","r",stdin);
    	freopen("Sakura.out","w",stdout);
    	int n,m,x,u,v,ans=0x7f7f7f7f,i;
    	cin>>n>>m>>x;
    	for(i=1;i<=m;i++)
    	{
    		cin>>u>>v;
    		add(u,v);
    		add(v,u);
    	}
    	bfs1(x);
    	bfs2();
    	for(i=head[n];i!=0;i=e[i].nxt)
    	{
    		if(dis[i]!=0x3f3f3f3f)
    		{
    			ans=min(ans,dis[i]);
    		}
    	}
    	if(ans==0x7f7f7f7f)
    	{
    		cout<<"No"<<endl;
    	}
    	else
    	{
    		cout<<"Yes"<<endl;
    		cout<<ans<<endl;
    	}
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    

\(T4\) P201. 机动车驾驶员考试 \(0pts\)

  • 原题: 2024牛客暑期多校训练营4 L Deceleration

  • 做法比较抽象,暴力代码都不知道怎么写,挂一下官方题解。

    发现无论以时间为轴维护距离,还是以距离为轴维护时间,都会遇到一个问题:取模之后无法比较大小,也就没法在平衡树里操作;线段树的深度会退化到 \(O(n)\)

    因此需要维护其他东西。

    定义“等效距离”,初始的剩余等效距离为 \(x\) ,每秒等效距离减 \(1\) ,那么每次速度减半就等价于剩余等效距离 \(\times 2\)

    构造一个时间为下标线段树,维护三个值:

    \(k\) : 区间减速次数。

    \(x\) : 至少需要多少等价距离才可以通过这个时间区间。

    \(r\) : 以 \(x\)(即最少需要的等价距离)的等价距离通过这个区间之后,还剩多少等价距离。

    注意,此时已经没有速度的概念了。减速已经转化为了等价距离这样的线断树就足以维护添加、合并、查询了。

    但是还有一些细节需要讨论:

    我们还需要维护 \(r\) 是否已经被取模过了。

    由于减速时间点最大为 \(10^9\) ,因此一旦等价距离被取模过 \(\ge 10^9\) ,则一定会通过所有时间节点。

    是否取模会有一些简单但繁琐的讨论,可以参考 std 代码。

    点击查看 std 代码
    #include <cstdio>
    #include <algorithm>
    
    using namespace std;
    
    const int max1 = 5e5;
    const int mod = 1e9 + 7;
    const int inf = 0x3f3f3f3f;
    
    int q;
    struct Question
    {
    	int op, x;
    }qus[max1 + 5];
    int save[max1 + 5], len;
    int power[max1 + 5];
    
    struct Data
    {
    	int L, R, x, k, r, op;
    
    	Data operator + ( const Data &A ) const
    	{
    		int dis = save[A.L] - save[R];
    		Data res;
    		res.L = L; res.R = A.R;
    		res.k = k + A.k;
    
    		if ( !op && !A.op )
    		{
    			if ( r - dis - A.x >= 0 )
    			{
    				res.x = x;
    
    				if ( A.k <= 30 )
    				{
    					long long p = (0LL + r - dis - A.x) * (1LL << A.k) + A.r;
    
    					if ( p >= mod )
    					{
    						res.op = 1;
    						res.r = p % mod;
    					}
    					else
    					{
    						res.op = 0;
    						res.r = p;
    					}
    				}
    				else if ( !(r - dis - A.x) )
    				{
    					res.op = 0;
    					res.r = A.r;
    				}
    				else
    				{
    					res.op = 1;
    					res.r = ((0LL + r - dis - A.x) * power[A.k] + A.r) % mod;
    				}
    			}
    			else
    			{
    				int c = ((A.x + dis - r - 1) >> min(31, k)) + 1;
    				res.x = x + c;
    
    				if ( k <= 30 && A.k <= 30 )
    				{
    					long long p = (0LL + r - dis - A.x + (c << k)) * (1LL << A.k) + A.r;
    					if ( p >= mod )
    					{
    						res.op = 1;
    						res.r = p % mod;
    					}
    					else
    					{
    						res.op = 0;
    						res.r = p;
    					}
    				}
    				else if ( k <= 30 && !(r - dis - A.x + (c << k)) )
    				{
    					res.op = 0;
    					res.r = A.r;
    				}
    				else
    				{
    					res.op = 1;
    					res.r = ((0LL + r - dis - A.x + 1LL * power[k] * c + mod) % mod * power[A.k] + A.r) % mod;
    				}
    			}
    		}
    		else if ( !op && A.op )
    		{
    			if ( r - dis - A.x >= 0 )
    			{
    				res.op = 1;
    				res.x = x;
    				res.r = ((0LL + r - dis - A.x) * power[A.k] + A.r) % mod;
    			}
    			else
    			{
    				int c = ((A.x + dis - r - 1) >> min(31, k)) + 1;
    				res.op = 1;
    				res.x = x + c;
    				res.r = ((0LL + r - dis - A.x + 1LL * power[k] * c + mod) % mod * power[A.k] + A.r) % mod;
    			}
    		}
    		else
    		{
    			res.x = x;
    			res.op = 1;
    			res.r = ((0LL + r - dis - A.x + mod) * power[A.k] + A.r) % mod;
    		}
    		return res;
    	}
    };
    
    struct Segment_Tree
    {
    	#define lson(now) (now << 1)
    	#define rson(now) (now << 1 | 1)
    
    	Data tree[max1 * 4 + 5], ans;
    
    	void Build ( int now, int L, int R )
    	{
    		if ( L == R )
    		{
    			tree[now].L = tree[now].R = L;
    			tree[now].x = tree[now].k = tree[now].r = 0;
    			tree[now].op = 0;
    			return;
    		}
    
    		int mid = (L + R) >> 1;
    		Build(lson(now), L, mid);
    		Build(rson(now), mid + 1, R);
    		tree[now] = tree[lson(now)] + tree[rson(now)];
    
    		// printf("Build L = %d R = %d x = %d k = %d r = %d op = %d\n", L, R, tree[now].x, tree[now].k, tree[now].r, tree[now].op);
    
    		return;
    	}
    
    	void Insert ( int now, int L, int R, int pos )
    	{
    		if ( L == R )
    		{
    			++tree[now].k;
    			return;
    		}
    
    		int mid = (L + R) >> 1;
    		if ( pos <= mid )
    			Insert(lson(now), L, mid, pos);
    		else
    			Insert(rson(now), mid + 1, R, pos);
    		
    		tree[now] = tree[lson(now)] + tree[rson(now)];
    		return;
    	}
    
    	void Query ( int now, int L, int R, int x )
    	{
    		if ( L == R )
    			return;
    		
    		int mid = (L + R) >> 1;
    		Data res = ans + tree[lson(now)];
    		if ( res.x > x )
    			Query(lson(now), L, mid, x);
    		else
    			ans = res, Query(rson(now), mid + 1, R, x);
    		return;
    	}
    }Tree;
    
    int main ()
    {
    	scanf("%d", &q);
    	for ( int i = 1; i <= q; i ++ )
    	{
    		scanf("%d%d", &qus[i].op, &qus[i].x);
    		if ( qus[i].op == 1 )
    			save[++len] = qus[i].x;
    	}
    	save[++len] = 0, save[++len] = inf;
    	sort(save + 1, save + 1 + len);
    	len = unique(save + 1, save + 1 + len) - (save + 1);
    
    	power[0] = 1;
    	for ( int i = 1; i <= q; i ++ )
    		power[i] = (power[i - 1] << 1) % mod;
    
    	Tree.Build(1, 1, len);
    
    	for ( int i = 1; i <= q; i ++ )
    	{
    		if ( qus[i].op == 1 )
    		{
    			qus[i].x = lower_bound(save + 1, save + 1 + len, qus[i].x) - save;
    			Tree.Insert(1, 1, len, qus[i].x);
    		}
    		else
    		{
    			Tree.ans.L = Tree.ans.R = 1;
    			Tree.ans.x = Tree.ans.k = Tree.ans.r = Tree.ans.op = 0;
    			int ans;
    
    			Tree.Query(1, 1, len, qus[i].x);
    			ans = (1LL * (qus[i].x - Tree.ans.x) * power[Tree.ans.k] % mod + Tree.ans.r + save[Tree.ans.R]) % mod;
    			printf("%d\n", ans);
    		}
    	}
    
    	return 0;
    }
    

总结

  • 赛时历程:看了眼题,发现题都不太可做。 \(T1\) 不想写类似 luogu P1654 OSU! 维护幂次的一大坨东西, \(T2\) 的暴力可写但分数太低, \(T3\) 口胡出了基环树的做法(但树的假了,反倒拿到了乱搞分), \(T4\) 题意理解有点问题,需要手摸样例。尝试继续想 \(T3\) 的结论无果发现之前基环树的做法是假的,然后恼了,打算先把昨天 \(T3\) 改了再来写这几题的暴力。然后我的键盘就因为前几天 @jijidawang 拉我被键盘线绊倒了,硬生生把 \(USB\) 接口掰弯了,当时以为没事,然后左 Shift 和左 Ctrl 用完之后各有 \(5 \sim 10s\) 内不能使用另一个,导致选中和复制粘贴即为麻烦。以为是电脑问题,把代码传到了 @Charlie_ljk 电脑上,然后就重启了,开机后键盘仍不能用,且 Shift 和 Ctrl 不能一直按,只能手动配 VSCode 设置,还一直显示有 hzoi 用户远程登录要关我机,但我拿终端的 who -u 显示只有我自己登录,可能是 \(feifei\) 以为我赛时传递代码作弊(?)。然后索性拿 @Charlie_ljk 电脑写代码了。改完昨天 \(T3\) 并写完今天 \(T2,T3\) 暴力后就看见改成了 \(IOI\) 赛制,然后就去手摸 \(T4\) 样例了,发现之前的修改时刻会对以后的所有修改时刻产生影响,离线下来建时刻线段树维护后缀乘的思路假了,然后就输出了 \(T1,T2,T3\) 的样例,并凭借测评机波动和减小常数让 \(T2\) 多过了 \(2\) 个点。输出完 \(T3\) 大样例后就结束了。

后记

  • 总-分-总

    • 赛前公告

    • \(9:30\) 时赛制改成了 \(IOI\) 赛制,并 适度 提醒做法。

    • 赛后题解补充

  • 组题人写的题面还是很抽象,理解和转化都需要一定时间。

  • 题目背景夹带私活。

posted @ 2024-08-17 17:53  hzoi_Shadow  阅读(59)  评论(3编辑  收藏  举报
扩大
缩小