首页 > 其他分享 >『模拟赛』暑假集训CSP提高模拟15

『模拟赛』暑假集训CSP提高模拟15

时间:2024-08-07 20:19:41浏览次数:11  
标签:ch 15 int sum ans mod CSP 模拟 回文

Rank

小寄一手

image

A. 串串

原[THUPC2018] 绿绿和串串

一眼 manacher,但是当时虚空了没搞懂,只打了暴力(还挂分了

稍微学了一下,板子很短,主要依据是可以通过一个已经确定的与目前最长回文串的中心对称的半径来预先确定目标点最短的回文半径长度,从而优化复杂度达到线性。

manacher 主要利用了回文串的一大性质:在一个回文串内任意一段区间,一定存在一个关于回文中心对称的区间,二者全等;若该区间是回文串,其对称区间也是回文串,二者回文半径相等。

根据这个性质,我们便可以在针对不同回文中心的求最大回文半径时预处理得到一个下界,由下界不断扩展得到真实的(最长)回文半径。手模一下很好理解,因为对称区间的半径到达极限,而目标区间的左侧与右侧还未进行查询,所以对称区间的回文半径是下界。按这样操作,最后复杂度为线性,在数据范围大的情况下优势尤为明显。

Manacher 模板

输入一个串,找到子串中最大回文串长度。

const int Ratio=0;
namespace Manachar
{
	string s;
	char ch[N];
	int len[N],cnt;
	short main()
	{
		cin>>s;
		int lenn=s.size(),ans=1;
		ch[0]='~',ch[1]='#';// 防越界
		for(int i=0;i<lenn;i++) ch[2*i+2]=s[i],ch[2*i+3]='#';
		cnt=2*lenn+1;
		ch[cnt+1]='%';
		int maxx=0,p=0;
		for(int i=1;i<=cnt;i++)
		{
			if(i<=maxx) len[i]=min(maxx-i+1,len[2*p]-i);
			while(ch[i-len[i]]==ch[i+len[i]]) len[i]++;
			if(len[i]+i>maxx) maxx=len[i]+i-1,p=i;
			if(len[i]>ans) ans=len[i];
		}
		printf("%d\n",ans-1);
		return Ratio;
	}
}
点击查看代码
#include<bits/stdc++.h>
#define fo(x,y,z) for(register int (x)=(y);(x)<=(z);(x)++)
#define fu(x,y,z) for(register int (x)=(y);(x)>=(z);(x)--)
using namespace std;
typedef long long ll;
#define lx int
inline lx qr()
{
	char ch=getchar();lx x=0,f=1;
	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);
	return x*f;
}
#undef lx
#define qr qr()
const int Ratio=0;
const int N=3e7+5;
const int mod=10007;
string s;
char ch[N];
int len[N],cnt;
bool yz[N];
namespace Wisadel
{
    short main()
    {
        // freopen(".in","r",stdin),freopen(".out","w",stdout);
        int T=qr;
        while(T--)
        {
            cin>>s;int lenn=s.size();
            ch[0]='~';ch[1]='#';
            fo(i,0,lenn-1) 
                ch[2*i+2]=s[i],ch[2*i+3]='#';
            cnt=2*lenn+1;
            ch[cnt+1]='%';
            int maxx=0,p=0;
            fo(i,1,cnt)
            {
                len[i]=0,yz[i]=0;
                if(i<=maxx) len[i]=min(maxx-i+1,len[2*p-i]);
                while(ch[i-len[i]]==ch[i+len[i]]) len[i]++;
                if(i+len[i]>maxx) maxx=i+len[i]-1,p=i;
            }
            fu(i,cnt,1)
                if(i+len[i]-1==cnt) yz[i]=1;
                else if(yz[i+len[i]-2]&&i==len[i]) yz[i]=1;
            fo(i,1,cnt) if(ch[i]>='a'&&ch[i]<='z'&&yz[i]) printf("%d ",i/2);
            printf("\n");
        }
        return Ratio;
    }
}
int main(){return Wisadel::main();}

B. 排排

躺尸题,结论找到了,但由于存在一点细节问题所以多测没清空挂 5pts。

听到没给大样例就能猜到答案应该就几个数而且很小。于是开始找结论:

  1. 当原排列本身单调递增时,答案显然为 0;
  2. 考虑答案为 1 的情况,在该排列中存在某一个位置上的数将序列左右划分的情况恰好与在升序排列中的情况相同,现上可以通过记录到每一位时的最大值来实现;
  3. 更大的答案我们通过逆推实现,我们取 1 在开头且不为结论 1 的情况,易得只需要取 \(k=1\) 一次操作即可达到要求,同理 n 在末尾亦如此,那么 1 不在开头且 n 不在末尾的情况答案显然为 2;
  4. 有没有更大的答案?考虑在结论 3 中找特殊情况,答案为 2 的前提是一次操作可以将 1 移到开头或将 n 移到末尾,考虑一次操作无法达到如上要求的情况,即无论如何取 \(k\) 的值都无法将 1 置于 \(k\) 左侧且无法将 n 置于 \(k\) 右侧,容易想到是 1 在末尾且 n 在开头的情况。

得出所有结论,问题就迎刃而解了。

点击查看代码
#include<bits/stdc++.h>
#define fo(x,y,z) for(register int (x)=(y);(x)<=(z);(x)++)
#define fu(x,y,z) for(register int (x)=(y);(x)>=(z);(x)--)
using namespace std;
typedef long long ll;
#define lx int
inline lx qr()
{
	char ch=getchar();lx x=0,f=1;
	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);
	return x*f;
}
#undef lx
#define qr qr()
const int Ratio=0;
const int N=3e5+5;
const int mod=10007;
int n;
int a[N];
priority_queue<int,vector<int>,less<int> >q;
namespace Wisadel
{
    short main()
    {
        int T=qr;
        while(T--)
        {
            n=qr;bool ok0=1,ok1=0;
            memset(a,0,sizeof a);
            while(q.size()) q.pop();
            fo(i,1,n)
            {
                a[i]=qr;
                if(a[i]!=i) ok0=0;
            }
            if(ok0){printf("0\n");continue;}
            if(a[1]==1||a[n]==n){printf("1\n");continue;}
            fo(i,1,n)
            {
                q.push(a[i]);
                if(q.top()==i&&a[i+1]==i+1){ok1=1;break;}
				// 笨重的方法不推荐使用,而且不加 memset 会 WA
            }
            if(ok1){printf("1\n");continue;}
            if(a[1]==n&&a[n]==1)printf("3\n");
            else printf("2\n");
        }
        return Ratio;
    }
}
int main(){return Wisadel::main();}

C. 序序

有点不可做的感觉。

赛时拿到了 10pts 的暴力并且推柿子拿到了特殊性质的 10pts,还可以。

先说说保证 \(s_i\le s_{i+1}\) 的做法。

已知序列单调不下降,那么最大值最小值乘积也显然为最左边的数乘上最右边的数,得到原始柿子:

\[ans=\sum_{i=L}^R \sum_{j=i}^R a_i\times a_j \]

求个前缀和,开推:

\[\begin{aligned} ans &= \sum_{i=L}^R \sum_{j=i}^R a_i\times a_j \\ &= \sum_{i=L}^R a_i\times\left(sum_R-sum_{i-1}\right) \\ &= a_L\times\left(sum_R-sum_{L-1}\right)+\ldots +a_R\times \left(sum_R-sum_{R-1}\right) \\ &= sum_R\times\left(sum_R-sum_{L-1}\right) - \sum_{i=L}^R a_i\times sum_{i-1} \end{aligned} \]

根据数据范围,我们知道但凡带 \(\sum\) 的都会使复杂度爆炸,因此我们每一步化简都要尽量消去它。

到这一步,我们发现如果再记录一个 \(a_i\times sum_{i-1}\) 这样的前缀和即可将最后一个 \(\sum\) 消去,最终结果为:

\[ans=sum_R\times\left(sum_R-sum_{L-1}\right)-\left(jsum_R-jsum_{L-1}\right) \]

点击查看代码
// 预处理
for(int i=1;i<=n;i++)
{
	cin>>a[i];
	sum[i]=(sum[i-1]+a[i])%mod;
	jsum[i]=(jsum[i-1]+a[i]*sum[i-1]%mod+mod)%mod;
}
// 查询
while(m--)
{
	int l,r;ll ans=0;
	cin>>l>>r;
	ans=(sum[r]-sum[l-1]+mod)%mod*sum[r]%mod;
	ans=(ans-(jsum[r]-jsum[l-1]+mod)%mod+mod)%mod;
	printf("%lld\n",ans);
}

D. 桥桥

原[APIO2019] 桥梁

暴力寄了挂 29pts。

虽然这次打的不太好,但感觉收获是很多的,学了 Manacher,吃了个多测的教训,因为大数组 memset 而 TLE,还推出来一个柿子。

所以高强度模拟赛就像题海,虽然这个受状态影响更大,但一样能收获很多小知识和经验教训,实力实在隐藏中提升的。

积少成多,加油。


完结撒花~

脑补一张飞霄老婆 wink 的图片。

标签:ch,15,int,sum,ans,mod,CSP,模拟,回文
From: https://www.cnblogs.com/Ratio-Yinyue1007/p/18347501

相关文章

  • 2024.8.7 模拟测
    A(P7968[COCI2021-2022#2]Osumnjičeni)考虑对于一次询问直接从左往右划分段,直至当前加入的人与前面某个人的身高有交集,则新开一个段。设\(nx_i=j\)表示从第\(i\)个人开始划分,要到第\(j\)个人才会出现冲突(若永远不会冲突则让\(nx_i=n+1\))。一次询问相当于初始时让......
  • 蒙特卡洛模拟(6)————旅行商问题
    旅行商问题(TravelingSalesmanProblem,TSP)是一个经典的组合优化问题。经典的TSP可以描述为:一个商品推销员要去若干个城市推销商品,该推销员从一个城市出发,需要经过所有城市后,回到出发地。应如何选择行进路线,以使总的行程最短。目录一、问题提出二、代码预备1.plot([a,b],[c,d])2.r......
  • 使用Streamlit构建一个web模拟HTTP请求工具
    目录前言HTTP工具功能点:1.导入库: 2.设置页面配置:3.Markdown格式的说明文本:4.用户输入界面:5.发送请求按钮和逻辑:6.发送HTTP请求并计算请求细节:7.总结 前言    最初就是因为在微信看到一篇文章中,看到此http工具的制作因为觉得Streamlit有无限......
  • [赛记] 暑假集训CSP提高模拟15
    原题还是没找串串49pts用的$manacher$,板子差点没打对,但好歹还是打对了。。。赛时写的时候没有考虑到不用管偶回文,导致递归的时候有点问题。。。其实根本用不到递归,将循环顺序改为倒序即可;有三种情况:回文半径+位置能够到达右端点;显然,这种情况是合法的;既到不了左......
  • LeetCode150 逆波兰表达式求值
    前言题目:150.逆波兰表达式求值文档:代码随想录——逆波兰表达式求值编程语言:C++解题状态:成功解答!思路还是利用栈的思想,遍历到数字时,加入栈,遍历到运算符时,取出两个数进行运算,并将结果加入到栈中。代码classSolution{public:intevalRPN(vector<string>......
  • fiddler - 对模拟器app抓包配置
    1.fiddler部分tools》options中, 这几个配置勾选跟我的一致,端口使用8888 然后导出证书 会导出到桌面 然后pc授信证书 然后重启fiddler 2.模拟器部分将证书拉入模拟器,然后点击证书安装,输入的名称可以随便写然后打开wlan,对wifi的修改代理为手动【模拟器有些......
  • 洛谷P1596 [USACO10OCT] Lake Counting S
    这种普通走迷宫的题,还是最好用bfs,毕竟复杂度是比dfs低的。但我这用dfs讲解。具体思路就不做详解,看代码注释。Code#include<bits/stdc++.h>usingnamespacestd;intn,m;chara[105][105];intdx[8]={0,1,-1,0,-1,1,-1,1};//搜索的八个方向常量,xintdy[8]={1,0......
  • 2024.8.7 模拟赛题解
    T1过于简单,不必阐述。T2给定一个仅包含\(A\)和\(P\)的字符串,每次操作可以删除相邻的\(AP\)或者\(PP\),问字符串最后的最小长度。$Sol:$为求最值问题,考虑贪心。先给出考场做法。发现若干的\(P\)是一定能合并掉的,于是贪心策略,就是如何最小化\(A\)的个数。对于每个......
  • 暑假集训CSP提高模拟15
    \[\color{red}{\huge囍挂111pts}\]叠词词恶心心T1串串一眼马拉车。我们来看看只翻转一次后就能得到答案的情况,就是如果某个位置的回文长度能到达这个字符串的末尾,那这个位置肯定能做翻转位置的,但是这种情况出现的位置只能在后半部分。如果是翻转多次的话,那么位置只能出现在......
  • 使用Cisco进行模拟配置OSPF路由协议
    OSPF路由协议1.实验目的1)理解OSPF2)掌握OSPF的配置方法3)掌握查看OSPF的相关信息2.实验流程开始→布置拓扑→配置IP地址→配置OSPF路由并验证PC路由的连通性→查看路由器路由信息→查看路由协议配置与统计信息→查看OSPF进程及区域信息→查看路由器OSPF数......