首页 > 其他分享 >多校A层冲刺NOIP2024模拟赛04

多校A层冲刺NOIP2024模拟赛04

时间:2024-10-09 18:02:01浏览次数:1  
标签:04 int ll 多校 len times char ans NOIP2024

多校A层冲刺NOIP2024模拟赛04

\(T1\) A. 02表示法 \(0pts/100pts\)

  • 弱化版: luogu P1010 [NOIP1998 普及组] 幂次方

  • 递归模拟即可,二进制分解时需要写高精除低精。

    点击查看代码
    int r[810],t[810];
    char s[810],id[810][10];
    string a;
    int chu(char s[])
    {
    	int n=strlen(s+1),x=0,tmp;
    	for(int i=1;i<=n;i++)
    	{
    		t[i]=s[n-i+1]-'0';
    	}
    	r[0]=0;
    	while(n>=1)
    	{
    		r[0]++;
    		r[r[0]]=t[1]%2;
    		x=0;
    		for(int i=n;i>=1;i--)
    		{
    			tmp=(t[i]+x*10)%2;
    			t[i]=(t[i]+x*10)/2;
    			x=tmp;
    		}
    		while(t[n]==0&&n>=1)
    		{
    			n--;
    		}
    	}
    	return r[0];
    }
    void divide(char s[])
    {
    	int tmp[710],n=chu(s),flag=0;
    	for(int i=1;i<=n;i++)
    	{
    		tmp[i]=r[i];
    	} 
    	for(int i=n;i>=3;i--)
    	{
    		if(tmp[i]==1)
    		{
    			if(flag==1)
    			{
    				cout<<"+";
    			}
    			cout<<"2(";
    			divide(id[i-1]);
    			cout<<")";
    			flag=1;
    		}
    	}
    	for(int i=2;i>=1;i--)
    	{
    		if(tmp[i]==1)
    		{
    			if(flag==1)
    			{
    				cout<<"+";
    			}
    			if(i==2)
    			{
    				cout<<"2";
    			}
    			else
    			{
    				cout<<"2(0)";
    			}
    			flag=1;
    		}
    	}
    }
    int main()
    {
    	freopen("power.in","r",stdin);//freopen("pow.in","r",stdin);
    	freopen("power.out","w",stdout);//freopen("pow.out","w",stdout);
    	for(int i=0;i<=800;i++)
    	{
    		a=to_string(i);
    		for(int j=0;j<a.size();j++)
    		{
    			id[i][j+1]=a[j];
    		}
    	}
    	cin>>(s+1);
    	divide(s);
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    

\(T2\) B. 子串的子串 \(100pts/100pts\)

  • 弱化版: luogu P2408 不同子串个数 | SP694 DISUBSTR - Distinct Substrings | SP705 SUBST1 - New Distinct Substrings

  • 强化版: luogu P6292 区间本质不同子串个数

  • 部分分

    • \(70 \sim 100 pts\) :对于每一组询问暴力重建后缀数组,时间复杂度为 \(O(nq \log n)\) 或 \(O(nq)\) 。
      • 题解

        点击查看代码
        int sa[6010],rk[6010],oldrk[6010],id[6010],cnt[6010],key[6010],height[6010];
        char s[6010],t[6010];
        int val(char x)
        {
        	return (int)x;
        }
        void counting_sort(int n,int m)
        {
        	for(int i=1;i<=m;i++)
        	{
        		cnt[i]=0;
        	}
        	for(int i=1;i<=n;i++)
        	{
        		cnt[key[i]]++;
        	}
        	for(int i=1;i<=m;i++)
        	{
        		cnt[i]+=cnt[i-1];
        	}
        	for(int i=n;i>=1;i--)
        	{
        		sa[cnt[key[i]]]=id[i];
        		cnt[key[i]]--;
        	}
        }
        void init(char s[],int len)
        {
        	int m=130,tot=0,num=0;
        	for(int i=1;i<=len;i++)
        	{
        		rk[i]=val(s[i]);
        		id[i]=i;
        		key[i]=rk[id[i]];
        	}
        	counting_sort(len,m);
        	for(int w=1;tot!=len;w<<=1,m=tot)
        	{
        		num=0;
        		for(int i=len;i>=len-w+1;i--)
        		{
        			num++;
        			id[num]=i;
        		}
        		for(int i=1;i<=len;i++)
        		{
        			if(sa[i]>w)
        			{
        				num++;
        				id[num]=sa[i]-w;
        			}
        		}
        		for(int i=1;i<=len;i++)
        		{
        			key[i]=rk[id[i]];
        		}
        		counting_sort(len,m);
        		for(int i=1;i<=len;i++)
        		{
        			oldrk[i]=rk[i];
        		}
        		tot=0;
        		for(int i=1;i<=len;i++)
        		{
        			tot+=(oldrk[sa[i]]!=oldrk[sa[i-1]]||oldrk[sa[i]+w]!=oldrk[sa[i-1]+w]);
        			rk[sa[i]]=tot;
        		}
        	}
        	for(int i=1,j=0;i<=len;i++)
        	{
        		j-=(j>=1);
        		while(s[i+j]==s[sa[rk[i]-1]+j])
        		{
        			j++;
        		}
        		height[rk[i]]=j;
        	}
        }
        ll ask(int l,int r)
        {
        	ll n=r-l+1,ans=n*(n+1)/2;
        	memset(t,0,sizeof(t));
        	for(int i=l;i<=r;i++)
        	{
        		t[i-l+1]=s[i];
        	}
        	init(t,n);
        	for(int i=1;i<=r-l+1;i++)
        	{
        		ans-=height[i];
        	}
        	return ans;
        }
        int main()
        {
        	freopen("substring.in","r",stdin);
        	freopen("substring.out","w",stdout);
        	int n,q,l,r,i;
        	scanf("%d%d%s",&n,&q,s+1);
        	for(i=1;i<=q;i++)
        	{
        		scanf("%d%d",&l,&r);
        		printf("%lld\n",ask(l,r));
        	}
        	fclose(stdin);
        	fclose(stdout);
        	return 0;
        }
        
      • \(hack\) 倍增进行后缀排序的数据生成器,生成的数据本地跑了 \(4s\) 。

        点击查看代码
        int main()
        {
        	int n=3000,q=20000;
        	cout<<n<<" "<<q<<endl;
        	for(int i=1;i<=n;i++)
        	{
        		cout<<"a";
        	}
        	cout<<endl;
        	for(int i=1;i<=q;i++)
        	{
        		cout<<1<<" "<<n<<endl;
        	}
        	return 0;
        }
        
  • 正解

    • 观察到 \(n\) 较小,考虑预处理出所有区间的答案,然后 \(O(1)\) 处理询问。
    • 设 \(ans_{l,r}\) 表示 \([l \sim r]\) 内本质不同的子串个数。不妨先处理出 \(ans\) 的差分数组再进行二维前缀和处理。
    • 类似区间 \(DP\) 的写法,枚举 \(s_{l \sim r}\) 这一子串,并得到它的哈希值。首先有 \(ans_{l,r}++\) ,又因为这一子串对上一次出现位置 \([l',r']\) 到 \([l,r]\) 的区间都有贡献,所以让 \(ans_{l',r'}--\) 。
    • 挑个好点的哈希模数和进制,数据略卡(尽管 \(std\) 写的是自然溢出)。
    • 在使用 unordered_map 后时间复杂度为 \(O(n^{2}+q)\) 。
    点击查看代码
    const ull base=13331;
    ull a[3010],jc[3010];
    int ans[3010][3010],w[3010][3010];
    char s[3010];
    unordered_map<ull,int>last;
    void sx_hash(char s[],ull a[],int len)
    {
    	for(int i=0;i<=len;i++)
    	{
    		a[i]=(i==0)?0:(a[i-1]*base+s[i]);	
    	}
    }
    ull ask_hash(int l,int r)
    {
    	return a[r]-a[l-1]*jc[r-l+1];
    }
    int main()
    {
    	freopen("substring.in","r",stdin);
    	freopen("substring.out","w",stdout);
    	int n,q,l,r,i,len;
    	cin>>n>>q>>(s+1);
    	for(i=0;i<=n;i++)
    	{
    		jc[i]=(i==0)?1:jc[i-1]*base;
    	}
    	sx_hash(s,a,n);
    	for(len=1;len<=n;len++)
    	{
    		last.clear();
    		for(l=1,r=l+len-1;r<=n;l++,r++)
    		{
    			ans[last[ask_hash(l,r)]][r]--;
    			ans[l][r]++;
    			last[ask_hash(l,r)]=l;
    		}
    	}
    	for(l=n;l>=1;l--)
    	{
    		for(r=l;r<=n;r++)
    		{
    			ans[l][r]+=ans[l+1][r]+ans[l][r-1]-ans[l+1][r-1];
    		}
    	}
    	for(i=1;i<=q;i++)
    	{
    		cin>>l>>r;
    		cout<<ans[l][r]<<endl;
    	}
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    

\(T3\) C. 魔法咒语 \(20pts/20pts\)

  • 部分分

    • \(20pts\) :模拟,时间复杂度为 \(O(n^{2}|s|^{3})\) 。

      点击查看代码
      string s[10010],pre,suf,tmp;
      unordered_map<string,bool>vis;
      int main()
      {
      	freopen("magic.in","r",stdin);
      	freopen("magic.out","w",stdout);
      	int n,i,j,k,h;
      	cin>>n;
      	for(i=1;i<=n;i++)
      	{
      		cin>>s[i];
      	}
      	for(i=1;i<=n;i++)
      	{
      		pre.clear();
      		for(j=0;j<s[i].size();j++)
      		{
      			pre+=s[i][j];
      			for(k=1;k<=n;k++)
      			{
      				suf.clear();
      				for(h=s[k].size()-1;h>=0;h--)
      				{
      					suf+=s[k][h];
      					tmp=pre;
      					reverse(suf.begin(),suf.end());
      					tmp+=suf;
      					vis[tmp]=1;
      					reverse(suf.begin(),suf.end());
      				}
      			}
      		}
      	}
      	cout<<vis.size()<<endl;
      	fclose(stdin);
      	fclose(stdout);
      	return 0;
      }
      
    • \(30pts\) :枚举所有的分割情况进行哈希判断,时间复杂度为 \(O(n^{2}|s|^{2})\) 。

  • 正解

    • 考虑将所有单词顺序插入第一棵 \(Trie\) 树上,倒序插入第二棵 \(Trie\) 树上。
    • 一个特别假的做法是在第一棵 \(Trie\) 树上访问的一个节点 \(x\) 时,若它的子节点中没有某个字母(假设为 \(c\) ),那么就加上第二棵 \(Trie\) 树的大小。
      • 问题在于可能会重复统计。
    • 解决重复统计的一个比较假的做法是在第一棵 \(Trie\) 树上访问的一个节点 \(x\) 时,若它的子节点中没有某个字母(假设为 \(c\) ),那么就加上以 \(c\) 开头的不同后缀数量。
      • 问题在于若存在一个以 \(c\) 结尾的单词,那么即使 \(x\) 的子节点中包含 \(c\) 也能拼出这个前缀 -c ,而对于上述做法统计不到这个贡献。
      • 例如 abc,dc 无法在上述做法通过 ab+c 得到的是 abc
    • 手动记录下上述贡献(不一定来自一个单词内部)即可。需要特判 \(|s|=1\) 。
    点击查看代码
    ll ed[30],flag[30];
    char s[50];
    ll val(char x)
    {
    	return x-'a'+1;
    }
    struct Trie
    {
    	ll son[400010][30],cnt[30],rt_sum=0;
    	void insert(char s[],ll len)
    	{
    		ll x=0;
    		for(ll i=1;i<=len;i++)
    		{
    			if(son[x][val(s[i])]==0)
    			{
    				rt_sum++;
    				son[x][val(s[i])]=rt_sum;
    				cnt[val(s[i])]++;
    			}
    			x=son[x][val(s[i])];
    		}
    	}
    }T[2];
    int main()
    {
    	freopen("magic.in","r",stdin);
    	freopen("magic.out","w",stdout);
    	ll n,len,ans=0,i,j;
    	cin>>n;
    	for(i=1;i<=n;i++)
    	{
    		cin>>(s+1);
    		len=strlen(s+1);
    		T[0].insert(s,len);
    		ed[val(s[len])]=1;
    		if(len==1)
    		{
    			ans+=(flag[val(s[len])]==0);
    			flag[val(s[len])]=1;
    		}
    		reverse(s+1,s+1+len);
    		T[1].insert(s,len);
    	}
    	for(i=1;i<=T[0].rt_sum;i++)
    	{
    		for(j=1;j<=26;j++)
    		{
    			if(T[0].son[i][j]==0)
    			{
    				ans+=T[1].cnt[j];
    			}
    			else
    			{
    				ans+=ed[j];
    			}
    		}
    	}
    	cout<<ans<<endl;
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    

\(T4\) D. 表达式 \(25pts/25pts\)

  • 部分分

    • 测试点 \(1 \sim 3\) :模拟,在使用扩展欧拉定理优化后时间复杂度为 \(O(nm \log \sqrt{p})\) ,实测可以额外通过测试点 \(14,17\) 。

      点击查看代码
      int a[200010],b[200010][2];
      char op[200010],s[200010];
      int get_phi(int n)
      {
      	int ans=n;
      	for(int i=2;i<=sqrt(n);i++)
      	{
      		if(n%i==0)
      		{
      			ans=ans/i*(i-1);
      			while(n%i==0)
      			{
      				n/=i;
      			}
      		}
      	}
      	if(n>1)
      	{
      		ans=ans/n*(n-1);
      	}
      	return ans;
      }
      int gcd(int a,int b)
      {
      	return b?gcd(b,a%b):a;
      }
      ll qpow(ll a,int b,int p)
      {
      	ll ans=1;
      	while(b)
      	{
      		if(b&1)
      		{
      			ans=ans*a%p;
      		}
      		b>>=1;
      		a=a*a%p;
      	}
      	return ans;
      }
      int qadd(int a,int b,int p)
      {
      	return a+b>=p?a+b-p:a+b;
      }
      void read(int pos,int p,int phi)
      {
      	scanf("%s",s+1);
      	int n=strlen(s+1);
      	op[pos]=s[1];
      	a[pos]=0;
      	if(op[pos]!='^')
      	{
      		for(int i=2;i<=n;i++)
      		{
      			a[pos]=qadd(a[pos]*10%p,s[i]-'0',p);
      		}
      	}
      	else
      	{
      		for(int i=2;i<=n;i++)
      		{
      			a[pos]=(a[pos]*10+s[i]-'0');
      		}
      		b[pos][0]=(a[pos]>=phi)?a[pos]%phi+phi:a[pos];
      		b[pos][1]=a[pos]%phi;
      	}
      }
      
      int main()
      {
      	freopen("expr.in","r",stdin);
      	freopen("expr.out","w",stdout);
      	int t,n,m,p,phi,pd,pos,last,flag,i,j;
      	ll x;
      	scanf("%d%d%d%d",&t,&n,&m,&p);
      	phi=get_phi(p);
      	for(i=1;i<=n;i++)
      	{
      		read(i,p,phi);
      	}
      	for(i=1;i<=m;i++)
      	{
      		scanf("%d",&pd);
      		if(pd==1)
      		{
      			scanf("%lld",&x);
      			last=flag=0;
      			for(j=1;j<=n;j++)
      			{
      				if(op[j]=='+')
      				{
      					x=qadd(x,a[j],p);
      					last=0;
      				}
      				if(op[j]=='*')
      				{
      					x=(x*a[j])%p;
      					last=0;
      				}
      				if(op[j]=='^')
      				{
      					if(last==0)
      					{
      						flag=(gcd(x,p)==1);
      					}
      					x=qpow(x,b[j][flag],p);
      					last=1;
      				}
      			}
      			printf("%lld\n",x);
      		}
      		else
      		{
      			scanf("%d",&pos);
      			read(pos,p,phi);
      		}
      	}
      	fclose(stdin);
      	fclose(stdout);
      	return 0;
      }
      
  • 正解

    • 观察到只有 \(1 \sim 3\) 的 \(p\) 比较大,而其他数据点的 \(p \le 46189\) ,且多为合数(例如 \(\begin{cases} 50=2 \times 5^{2} \\ 100=2^{2} \times 5^{2} \\ 10800=2^{4} \times 3^{3} \times 5^{2} \\ 12673=19 \times 23 \times 29 \\ 46189=11 \times 13 \times 17 \times 19 \\ 1001=7 \times 11 \times 13 \\ 29393=7 \times 13 \times 17 \times 19 \end{cases}\) ),考虑面向数据点分治,以下只讲解测试点 \(4 \sim 20\) 。
    • 考虑线段树的每个节点 \([l,r]\) 维护一个 \(\{ val \}\) ,且 \(val_{x}\) 表示将 \(x\) 放在 \([l,r]\) 的表达式开头最终能得到的结果。
    • 接着充分利用 \(p\) 多为合数的性质,将 \(p\) 质因数分解后线段树求出对 \(p_{i}^{c_{i}}\) 取模后的结果,使用 \(CRT\) 合并即可。
    点击查看代码
    
    

总结

  • \(T1\) 浪费的时间太多了(写了约 \(2h\) ),导致没有时间写 \(T4\) 的测试点 \(10\) 了;没有注意到 accoders NOI 和学校 \(OJ\) 的文件 \(IO\) 不一样,挂了 \(100pts\) 。
  • \(T4\) 以为对于大部分 \(p\) 都有通用性做法,所以没想到数据点分治;但看到后面测试点的指数远大于 \(p\) 就一眼想到扩展欧拉定理优化了,挺好。

后记

  • \(7:05\) 去吃早饭时 accoders NOI 上开始时间还是 \(7:30\) ,吃完饭回来后就发现改成了 \(7:15\) ,而学校 \(OJ\) 还是 \(7:30\) 开始,遂“被迫”提前开题。
  • \(T4\) 数据范围没写在下发的题面 PDF 里,而是单独作为 jpg 在学校 \(OJ\) 下发了二次而且不一样(第一次的直接提示了 \(\sigma(p)\) 很小,但因为是刚开题导致没有细想)。

标签:04,int,ll,多校,len,times,char,ans,NOIP2024
From: https://www.cnblogs.com/The-Shadow-Dragon/p/18454800

相关文章

  • IEC104规约的秘密之七----配置参数t1,t2,t3
    104通讯前需要配置通讯参数,一般有如下参数:IP地址,端口号,k,w,t1,t2,t3,公共地址,遥控超时参数,104主规约还有一个t0参数。本次只讲解t1,t2,t3这两个参数。这三个都是超时时间,t1用于两个地方,一个是发送的I帧没有得到及时的确认,在规约文本中有如下图:B站发送I(0,0)帧后,开始计时,A站回......
  • C++ day04(友元 friend、运算符重载、String字符串)
    目录【1】友元friend1》概念2》友元函数 3》友元类 4》友元成员函数 【2】运算符重载1》概念2》友元函数运算符重载 ​编辑 3》成员函数运算符重载4》赋值运算符与类型转换运算符重载 5》注意事项【3】String字符串类【1】友元friend1》概念定义:......
  • XYD1004CSPS
    T1序列[贪心,模拟]Description给定一个序列,每次可以将一个数减一,求让所有数字互不相同的最小操作数,\(0\)除外,也就是\(0\)可以相同。Solution贪心地,从大到小考虑每个数,都只需要减到第一个没有数出现的数。开个桶从大到小累计答案即可。T2XYD[构造]Description给定\(......
  • 【堆】【优先队列】[NOIP2004]合并果子
    https://ac.nowcoder.com/acm/contest/22669/I堆的用法Type:队列中存储元素的类型。例如int,double,pair<int,int>等。Container:底层存储数据的容器类型,默认为vector,但可以换成deque或其他容器。Compare:比较函数,用于决定优先级顺序。默认是less,表示最大堆。如果使用......
  • 20241008_Day 04
    helloworld!1.安装NOTEPAD++2.新建代码文件夹3.新建JAVA文件1.可以新建text文件,修改后缀为.java2.打开方式修改为notepad+++4.编写代码具体为:javapublicclassHello{publicstaticvoidmain(String[]args){System.out.print("Hello,world!");}}5.......
  • 2018_11_02_04
    vue-cli案例constpath=require('path');functionresolve(dir){returnpath.join(__dirname,dir);}consttargetUrl='[地址]';module.exports={//Projectdeploymentbase//Bydefaultweassumeyourappwillbedeployedatthe......
  • NOIP2024集训 Day47 总结
    前言人有两次生命,当他意识到只有一次的时候,第二次生命就开始最小生成树和二分图匹配专题,感觉总体都比较套路。但是这些套路为啥感觉见都没见过啊,怪不得做这么慢。色观察到对于最终答案显然都是最小生成树上一条两个端点颜色不同的边。而这个题并不会改变图的形态,仅仅是改......
  • NOIP2024集训Day47 生成树+二分图
    NOIP2024集训Day47生成树+二分图B.[THUPC2022初赛]最小公倍树直接建边显然不行,考虑优化建边。对于两个点\(u,v\),\((u,v)\)的边权为\(\displaystyle\operatorname{lcm}(u,v)=\frac{u\timesv}{\gcd(u,v)}\),显然应该选择\(\gcd(u,v)\)尽可能大的点对连边,也就是......
  • 2018_11_02_04
    instanceof运算符原文语法objectinstanceofconstructor参数object要检测的对象.constructor某个构造函数描述instanceof运算符用来检测constructor.prototype是否存在于参数object的原型链上。//定义构造函数functionC(){}functionD(){}varo=......
  • ELX304 – Electronic Systems
    ELX304–ElectronicSystemsIndividualCourseworkAssignmentDigitalDesignSUBMISSIONONLINEon13/10/2024viaCANVASIntroductionThiscourseworkexercisewillprovideyouwiththeopportunitytodemonstratetheskillsyouhavedevelopedthroughout......