首页 > 其他分享 >NOIP2024 前集训:多校A层冲刺NOIP2024模拟赛19

NOIP2024 前集训:多校A层冲刺NOIP2024模拟赛19

时间:2024-11-08 16:08:26浏览次数:1  
标签:unlocked 19 void 多校 Tp write int inline NOIP2024

前言

这次不是之前学长吃完吐出来的 shi,这次是新拉的热乎的烫嘴的 shi。

T1、2、3、4 大样例全部错一遍,T1 题面和时限再错一遍哈哈哈。

T4 假做法有 60 哈哈哈,大样例跑出来半个对的都没有能得 60 哈哈哈。

accoders T1 前半小时没数据做得快的全部都死哈哈(还好我第一份被卡常了后来又交了一份过了)。

T1 图书管理

中位数经典套路,枚举 \(a_i\),\(>a_i\) 的变为 \(1\),\(<a_i\) 的变为 \(-1\),那么如果存在左右端点内的和为 \(0\) 则 \(a_i\) 是这个区间的中位数,左区间先扫一遍扔桶里右区间再统计答案即可,复杂度 \(O(n^2)\),用 STL 会被卡常,建议用数组。

  • 然后竟然真的有人打 \(O(n^2\log n)\) 的部分分,就是用对顶堆什么的暴力跑,之前没听说过这玩意啊,学了一下,但是部分分真不是比正解难想又难打?
点击查看代码
#include<bits/stdc++.h>
#pragma GCC optimize(3)
#define ll long long
#define endl '\n'
#define sort stable_sort
using namespace std;
const int N=1e4+10;
template<typename Tp> inline void read(Tp&x)
{
	x=0;register bool z=true;
	register char c=getchar_unlocked();
	for(;!isdigit(c);c=getchar_unlocked()) if(c=='-') z=0;
	for(;isdigit(c);c=getchar_unlocked()) x=(x<<1)+(x<<3)+(c^48);
	x=(z?x:~x+1);
}
template<typename T,typename ...Tp> inline void read(T &x,Tp &...y){read(x);read(y...);}
template<typename Tp> inline void wt(Tp x){if(x>9)wt(x/10);putchar_unlocked((x%10)+'0');}
template<typename Tp> inline void write(Tp x){if(x<0)putchar_unlocked('-'),x=~x+1;wt(x);}
template<typename T,typename ...Tp> inline void write(T x,Tp ...y){write(x);putchar_unlocked(' ');write(y...);}
int n,a[N],b[N],sum[N<<1]; ll ans,res;
signed main()
{
	freopen("book.in","r",stdin),freopen("book.out","w",stdout);
	read(n); for(int i=1;i<=n;i++) read(a[i]);
	for(int i=1;i<=n;ans+=res*a[i++],res=0,memset(sum,0,sizeof(sum)))
	{
		for(int j=1;j<=n;j++) b[j]=a[j]>a[i]?1:-1; b[i]=0;
		for(int j=i,pre=0;j;j--) pre+=b[j],sum[pre+n]+=j;
		for(int j=i,suf=0;j<=n;j++) suf+=b[j],res+=1ll*sum[n-suf]*j;
	}
	write(ans);
}

T2 两棵树

结论题:树(森林)的连通块数 \(=\) 点数 \(-\) 边数

那么结果可以拆成 \(点_U\times 点_T-点_U\times 边_T-边_U\times 点_T+边_U\times 边_T\)。 统计这四部分的贡献即可。

  • \(点\times 点\):设 \(x,u\) 分别表示 \(U,T\) 中一点,则 \(x,u\) 同时存在的概率等于 \([x\ne u]\dfrac{1}{4}\),所以该部分答案为 \(\dfrac{n(n-1)}{4}\)。

  • \(点\times 边\):设 \(x\) 表示 \(U\) 中一点,\((u,v)\) 表示 \(T\) 中一边,则 \(x,(u,v)\) 同时存在概率为 \([x\ne u \wedge x\ne v]\dfrac{1}{8}\),这个贡献要 \(\times -2\)。

  • \(边\times 边\):设 \((x,y),(u,v)\) 分别表示 \(U,T\) 中一边,则 \((x,y),(u,v)\) 同时存在概率为 \([x\ne u\wedge x\ne v\wedge y\ne u\wedge y\ne v]\dfrac{1}{16}\),可以枚举 \(U\) 中边 \((x,y)\),则该条边的贡献为 \(\dfrac{n-1-deg_x-deg_y+[(u,v)=(x,y)]}{16}\),\([(u,v)=(x,y)]\) 表示 \(T\) 中存在 \((u,v)=(x,y)\)。

最后都加起来即可。

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define sort stable_sort
using namespace std;
const int N=2e5+10,P=998244353;
template<typename Tp> inline void read(Tp&x)
{
	x=0;register bool z=true;
	register char c=getchar_unlocked();
	for(;!isdigit(c);c=getchar_unlocked()) if(c=='-') z=0;
	for(;isdigit(c);c=getchar_unlocked()) x=(x<<1)+(x<<3)+(c^48);
	x=(z?x:~x+1);
}
template<typename T,typename ...Tp> inline void read(T &x,Tp &...y){read(x);read(y...);}
template<typename Tp> inline void wt(Tp x){if(x>9)wt(x/10);putchar_unlocked((x%10)+'0');}
template<typename Tp> inline void write(Tp x){if(x<0)putchar_unlocked('-'),x=~x+1;wt(x);}
template<typename T,typename ...Tp> inline void write(T x,Tp ...y){write(x);putchar_unlocked(' ');write(y...);}
int n,ans,deg[N]; set<int>vis[N];
inline int mod(int x,int y) {return (x+=y)>=P?x-P:x;}
signed main()
{
	freopen("tree.in","r",stdin),freopen("tree.out","w",stdout);
	read(n); for(int i=1,x,y;i<n;i++)
	{
		read(x,y),(x>y)&&(x^=y^=x^=y);
		deg[x]++,deg[y]++,vis[x].insert(y);
	}
	for(int i=1,x,y;i<n;i++)
	{
		read(x,y),(x>y)&&(x^=y^=x^=y);
		ans=mod(ans,n-1-deg[x]-deg[y]+vis[x].count(y));
	}
	write((935854081ll*ans%P+499122177ll*(n-1)%P)%P);
}

T3 函数

  • 部分分 \(60pts\):暴力也能拿这个分,真正应该拿到这个分的是可持久化 01trie,找二分 \([l,mid]\) 中最大值与最小值是否异号,复杂度 \(O(n\log n\log v)\)。

  • 正解:

    判无解是容易的,找到最大值和最小值,判断二者是否异号即可,设其位置为 \(l,r\)。

    若有解,那么目前满足 \(l,r\) 异号,二分一个 \(mid\),一定满足 \(mid\) 和 \(l,r\) 中的一个异号,由此二分不断缩小范围最后找到答案,复杂度 \(O(n(\log n+\log v))\)。

    点击查看代码
    #include<bits/stdc++.h>
    #pragma GCC optimize(3)
    #define ll long long
    #define endl '\n'
    #define sort stable_sort
    using namespace std;
    const int N=1e6+10,M=3e7+10;
    template<typename Tp> inline void read(Tp&x)
    {
    	x=0;register bool z=true;
    	register char c=getchar_unlocked();
    	for(;!isdigit(c);c=getchar_unlocked()) if(c=='-') z=0;
    	for(;isdigit(c);c=getchar_unlocked()) x=(x<<1)+(x<<3)+(c^48);
    	x=(z?x:~x+1);
    }
    template<typename T,typename ...Tp> inline void read(T &x,Tp &...y){read(x);read(y...);}
    template<typename Tp> inline void wt(Tp x){if(x>9)wt(x/10);putchar_unlocked((x%10)+'0');}
    template<typename Tp> inline void write(Tp x){if(x<0)putchar_unlocked('-'),x=~x+1;wt(x);}
    template<typename T,typename ...Tp> inline void write(T x,Tp ...y){write(x);putchar_unlocked(' ');write(y...);}
    int n,m,tot=1,s[N],pos[M],t[M][2];
    inline void insert(int x,int id,int p=1)
    {
    	for(int i=29,c;~i;i--,p=t[p][c])
    		(!t[p][c=(x>>i)&1])&&(t[p][c]=++tot);
    	pos[p]=id;
    }
    inline int ask(int x,int v,int p=1)
    {
    	for(int i=29,c;~i&&p;i--)
    		t[p][(c=(x>>i)&1)^v]?p=t[p][c^v]:p=t[p][c^(!v)];
    	return pos[p];
    }
    signed main()
    {
    	freopen("fun.in","r",stdin),freopen("fun.out","w",stdout);
    	read(n,m); for(int i=1;i<=n;i++) read(s[i]),insert(s[i],i);
    	for(int a,b,l,r,mid;m;m--)
    	{
    		read(a,b),l=ask(a,1),r=ask(a,0);
    		if((!((s[l]^a)-b>0)^((s[r]^a)-b>0))) {puts("-1"); continue;}
    		for((l>r)&&(l^=r^=l^=r);l+1<r;)
    			(((s[mid=l+r>>1]^a)-b>0)^((s[r]^a)-b>0))?l=mid:r=mid;
    		write(l),puts("");
    	}
    }
    

T4 编辑

  • 部分分 \(60pts\):

    \(O(n^3)\) DP 是显然的,对于两个串 \(s,t\),设 \(f_{i,j}\) 表示 \(s\) 的前 \(i\) 位和 \(t\) 的前 \(j\) 位匹配最少需要的操作数,有 \(f_{i,j}=\min(f_{i-1,j}+1,f_{i,j-1}+1,f_{i-1,j-1}+[s_i\ne t_j])\),这个 DP 可以继承,所以是 \(O(n^3)\) 的。

    但是发现他和最长公共子序列的转移是那么的相似,完全就是这个 DP 反过来,那么是不是用什么玩意儿减去最长公共子序列长度即可?但事实证明完全不对,大样例跑出来和答案一毛不一样,唉但是他交上去也有 \(60\),奇怪不奇怪?

  • 正解:

    发现上面那个做法单次 DP 是 \(O(n^2)\) 的因为 \(n\) 很大,发现 \(k\) 很小,考虑设计状态时改成和 \(k\) 相关的,从而使单次复杂度变为 \(O(k^2)\)。

    设 \(f_{i,j}\) 表示操作 \(i\) 次,二者长度差为 \(j\) 时最大的匹配长度(\(j\) 可以 \(<0\))。

    对于每一种状态确定了下一次匹配的起点,\(s\) 的起点是 \(f_{i,j}+1\),\(t\) 的起点是 \(f_{i,j}+j+1\),此时可以跳过一些已经匹配好的,即二者此时的最长公共前缀,这个是后缀数组板子,二分哈希也能做(但复杂度不太正确),即:

    \[f_{i,j}=f_{i,j}+lcp(s[f_{i,j}+1,|s|],t[f_{i,j}+j+1,|t|]) \]

    接下来考虑转移:

    \[\begin{cases}f_{i+1,j-1}=\max(f_{i+1,j-1},f_{i,j}+1)\\f_{i+1,j}=\max(f_{i+1,j},f_{i,j}+1)\\f_{i+1,j+1}=\max(f_{i+1,j+1},f_{i,j})\\\end{cases} \]

    分别对应添加、修改和删除操作。

    由此枚举起点跑 DP 即可,发现 \(i\in[0,k],j\in[-k,k]\),所以单次 DP 复杂度为 \(O(k^2)\),总复杂度为 \(O(nk^2)\)(用二分哈希多个 \(\log\))。

    点击查看代码
    #include<bits/stdc++.h>
    #pragma GCC optimize(3)
    #define ll long long
    #define endl '\n'
    #define sort stable_sort
    using namespace std;
    const int N=1e5+10;
    template<typename Tp> inline void read(Tp&x)
    {
    	x=0;register bool z=true;
    	register char c=getchar_unlocked();
    	for(;!isdigit(c);c=getchar_unlocked()) if(c=='-') z=0;
    	for(;isdigit(c);c=getchar_unlocked()) x=(x<<1)+(x<<3)+(c^48);
    	x=(z?x:~x+1);
    }
    template<typename T,typename ...Tp> inline void read(T &x,Tp &...y){read(x);read(y...);}
    template<typename Tp> inline void wt(Tp x){if(x>9)wt(x/10);putchar_unlocked((x%10)+'0');}
    template<typename Tp> inline void write(Tp x){if(x<0)putchar_unlocked('-'),x=~x+1;wt(x);}
    template<typename T,typename ...Tp> inline void write(T x,Tp ...y){write(x);putchar_unlocked(' ');write(y...);}
    int k,n,m,res,f[35][65],ans[35]; char s[N],t[N>>1];
    class suffix_array 
    {
    	private:
    		int n,sa[N],rk[N],id[N],cnt[N],key[N],oldrk[N],height[N],mn[20][N];
    		inline void count_sort(int n,int m)
    		{
    			memset(cnt,0,4*(m+1));
    			for(int i=1;i<=n;i++) cnt[key[i]=rk[id[i]]]++;
    			for(int i=1;i<=m;i++) cnt[i]+=cnt[i-1];
    			for(int i=n;i;i--) sa[cnt[key[i]]--]=id[i];
    		}
    	public:
    		inline void init(int len)
    		{
    			n=len; int m=27,w,tot=0,num=0;
    			for(int i=1;i<=n;i++) rk[id[i]=i]=s[i]-'a'+1,key[i]=rk[id[i]];
    			for(count_sort(n,m),w=1;w<n&&tot!=n;w<<=1,m=tot,num=0)
    			{
    				for(int i=n;i>=n-w+1;i--) id[++num]=i;
    				for(int i=1;i<=n;i++) (sa[i]>w)&&(id[++num]=sa[i]-w);
    				count_sort(n,m),memcpy(oldrk,rk,4*(n+1)),tot=0;
    				for(int i=1;i<=n;i++)
    					rk[sa[i]]=(tot+=(oldrk[sa[i]]!=oldrk[sa[i-1]]||oldrk[sa[i]+w]!=oldrk[sa[i-1]+w]));
    			}
    			for(int i=1,k=0;i<=n;i++) if(rk[i])
    			{for(k-=!!k;s[i+k]==s[sa[rk[i]-1]+k];k++); height[rk[i]]=k;}
    			memset(mn,0x3f,sizeof(mn));
    			for(int i=1;i<=n;i++) mn[0][i]=height[i];
    			for(int i=1;i<=__lg(n);i++) for(int j=1;j<=n;j++)
    				mn[i][j]=min(mn[i-1][j],mn[i-1][j+(1<<(i-1))]);
    		}
    		inline int lcp(int l,int r,int t=0)
    		{
    			((l=rk[l])>(r=rk[r]))&&(l^=r^=l^=r),t=__lg(r-(++l)+1);
    			return (!l||!r)?0:min(mn[t][l],mn[t][r-(1<<t)+1]);
    		}
    }sa;
    inline int lcp(int x,int y) {return min({sa.lcp(x,n+y+1),n-x+1,m-y+1});}
    inline void solve(int st)
    {
    	memset(f,-1,sizeof(f)),f[0][k]=0;
    	for(int i=0;i<=k;i++) for(int j=0,h;j<=(k<<1);j++) 
    		if(f[i][j]!=-1&&f[i][j]+(h=j-k)>=0&&st+f[i][j]+h-1<=m)
    		{
    			f[i][j]+=lcp(f[i][j]+1,st+f[i][j]+h);
    			if(i==k) continue;
    			(j)&&(f[i+1][j-1]=max(f[i+1][j-1],f[i][j]+(f[i][j]!=n)));
    			f[i+1][j]=max(f[i+1][j],f[i][j]+(f[i][j]!=n));
    			f[i+1][j+1]=max(f[i+1][j+1],f[i][j]);
    		}
    	for(int i=0;i<=(k<<1);i++) for(int j=0;j<=k;j++)
    		if(f[j][i]==n&&i-k+n>0&&st+i-k+n-1<=m) {ans[j]++; break;}
    }
    signed main()
    {
    	freopen("edit.in","r",stdin),freopen("edit.out","w",stdout);
    	read(k),scanf("%s%s",s+1,t+1),n=strlen(s+1),m=strlen(t+1);
    	s[n+1]='{',strcat(s+1,t+1),sa.init(n+m+1);
    	for(int i=1;i<=m;i++) solve(i);
    	for(int i=0;i<=k;i++) write(ans[i]),puts("");
    }
    

标签:unlocked,19,void,多校,Tp,write,int,inline,NOIP2024
From: https://www.cnblogs.com/Charlieljk/p/18535311

相关文章

  • 20240919 短时赛
    20240919短时训练赛AShuffle赛时一直不知道怎么不重,唐了两个小时。注意到\(n\leq5000\),那么先\(O(n^2)\)枚举发生变化的第一个数和最后一个数,这两个位置不同时方案显然不同,于是不会算重。发生变化的这两个数强制改,剩下的乱放,组合数算一下就好。BRainCXORTree注......
  • CF1995 题解
    B有n种物品,每种物品价格为$a_i$,数量为$c_i$。要求选取物品的方案,满足价格极差不超过1,价格总和不超过m。最大化价格总和。$n\le10^5,m\le10^{18},a_i,c_i\le10^9,a_i\neqa_j$显然只有\(x\)和\(x,x+1\)两种选择情况。\(x\)直接贪心选即可,考虑\(x,x+1\)。发......
  • AbMole | MRTX1133(CAS号2621928-55-8;目录号M10593)
    MRTX1133是一种首创的(first-in-class),高度选择性的突变体KRASG12D的抑制剂,可逆地结合激活和失活的KRASG12D突变体并抑制其活性。MRTX1133对KRASG12D的特异性是野生型KRAS的1000倍以上。生物活性MRTX1133是一种有效的、高选择性的KRASG12D抑制剂。MRTX1133......
  • 【ALINX 教程分享】基于 Z19-P 开发板实现 WIFI 无线通信的功能
     本教程基于ALINX开发板Z19-P,实现WIFI 无线通信的功能,WIFI模块使用 USB WIFIrtl8188cu。使用的usbwifi设备购买链接:http://e.tb.cn/h.gy25HiTTj7n5eNg?tk=zvvU3oWX4X特别提醒,本教程Z19-P所使用的 Linux环境是按照教程“Xilinx开发环境安装教程”搭建的,请......
  • [赛记] NOIP2024加赛1 && 多校A层冲刺NOIP2024模拟赛18
    暴力错解大赛玩游戏82pts乱糊的错解,正确性和时间复杂度都不对,但是拿了82pts;对于正解,考虑从$k$将原序列分成两个部分,左边和右边,然后分别求一次前缀和(注意这里,可以省去很多分讨和常数),设前一个前缀和数组为$a$,后一个为$b$,那么问题就转化成有两个指针$i,j$,可以任......
  • Microsoft Office 2019 (office全家桶)for Mac/Windows电脑安装包
    MicrosoftOffice2019forMac(Office全家桶)是一款功能全面且强大的办公软件套件,专为Mac用户设计。Mac苹果电脑下载:Office2019(含激活秘钥)Windows电脑下载:Office2019(含批量许可)    以下是其主要特点和优势:一、界面设计采用了Mac系统的设......
  • 多校A层冲刺NOIP2024模拟赛19
    多校A层冲刺NOIP2024模拟赛19其实不太想写博客,但还是从今天开始坚持写吧。T1图书管理对于这种一边大一边小的问题,一般套路是大的设为$1$,小的设为$-1$,这道题也是,这样之后去扫一遍,两端的前缀和值一样即可。T2两棵树新学到的一个重要$trick$是:$$连通块的个数......
  • P9192 [USACO23OPEN] Pareidolia P 题解
    P9192[USACO23OPEN]PareidoliaP题解首先自然考虑不带修的情况。考虑问题的本质就是求序列中尽量短的bessie序列个数。对于尽量短的理解是对于bessiebessie序列,不考虑其由\(1,8\sim12\)构成的序列,只考虑\(1\sim6,7\sim12\)组成的序列。于是考虑dp:设\(dp_{i......
  • [63] (多校联训) A层冲刺NOIP2024模拟赛19
    lhx对\((\lnn)^{\lnn}\)求导求出一个形如\(\frac{1}{n\lnn\ln\lnn}\)的东西A.图书管理说一种很好玩的\(n^2\logn\)做法(因为动态中位数我只会这个)对顶堆:就是你开一个大根堆和一个小根堆,然后把它们怼在一起,钦定比中位数大的放小根堆,小的放大根堆,这样中间就是中位......
  • CF1956F Nene and the Passing Game 题解
    处理很妙的题,部分细节请教了未来姚班zyl和LYH_cpp,在此鸣谢。首先考虑把题目给的式子进行转化,设\(i<j\),那么\(i\)和\(j\)能传球当且仅当\(l_i+l_j\lej-i\ler_i+r_j\)。移项并拆开得到,\(i+l_i\lej-l_i\)且\(i+r_i\gej-r_j\),如果画到数轴上的话......