首页 > 其他分享 >11.21

11.21

时间:2024-11-21 18:18:46浏览次数:1  
标签:int 11.21 leq times10 define sum mod

如何评价 OI 赛制无 pretest 仅有至多两个 CF 同等强度的极小样例?
340->170 是最好的答案。

A.括号序列

每个括号找出和它匹配的括号,同时求出 \(pre_i\) 和 \(nxt_i\) 分别代表与 \(i\) 同层的前缀括号匹配数和后缀括号匹配数,那么当前层给 \(i\) 贡献为 \((pre_i+1)\times(suf_{r_i}+1)\),差分维护就好。

点击查看代码
#include <bits/stdc++.h>
#define fr first
#define se second
#define Un unsigned
#define LL long long
#define pb push_back
#define pii pair<int,int>
#define pLi pair<LL,int>
#define pLL pair<LL,LL>
#define __ __int128
#define LD long double
#define VE vector<LL>
#define DB double
#define Ve vector<int>

using namespace std;

const int P = 1e9+7,N = 1e7+5;
int stk[N],top,pre[N],suf[N],l[N],r[N];
LL a[N];

int main()
{
	freopen("bracket.in","r",stdin);
	freopen("bracket.out","w",stdout);
	ios::sync_with_stdio(0);
	string s;cin >> s;int n = s.size();
	for (int i = 0;i < n;i++)
	{
		if (s[i] == '(') stk[++top] = i+1;
		else if(top) r[stk[top]] = i+1,l[i+1] = stk[top],top--;
	}
	for (int i = 1;i <= n;i++)
		if (s[i-1] == ')' && l[i]) pre[i] = pre[l[i]-1]+1;
	for (int i = n;i >= 1;i--)
		if (s[i-1] == '(' && r[i]) suf[i] = suf[r[i]+1]+1;
	for (int i = 1;i <= n;i++)
		if (s[i-1] == '(' && r[i]) a[i] += 1LL*(pre[i-1]+1)*(suf[r[i]+1]+1),a[r[i]+1] -= 1LL*(pre[i-1]+1)*(suf[r[i]+1]+1);
	LL ans = 0;
	for (int i = 1;i <= n;i++) a[i] += a[i-1],ans = ans+(a[i]*i)%P;
	cout << ans;
	return 0;
}

B.序列划分

设 \(h_i\) 表示 \(1\sim i\) 字符构成的十进制数字,即 \(h_i=\sum\limits_{j=1}^{i}s_i10^{i-j}\) 。

一个子串 \([l,r]\) 构成的十进制数字能整除 \(D\) 当且仅当 \(h_r-h_{l-1}\times10^{r-l+1}\equiv0\pmod D\) ,也就是说 \(h_r\equiv h_{l-1}\times10^{r-l+1}\pmod D\)。

设 \(f_i\) 为以 \(i\) 为结尾子串不能被 \(D\) 整除的前 \(i\) 个字符的划分方案数,\(g_i\) 为以 \(i\) 为结尾子串能被 \(D\) 整除的前 \(i\) 个字符的划分方案数,

每次转移 \(f_i=\sum\limits_{h_i-h_{j-1}\times10^{i-j+1}\not\equiv0\pmod D}g_j\),\(g_i=\sum\limits_{h_r-h_{l-1}\times10^{r-l+1}\equiv0\pmod D}f_j+g_j\)。

暴力向前扫是 \(O(n^2)\) 的,考虑优化。

若 \(\gcd(10,D)=1\),那么上述同余方程可以写成 \(h_r\times10^{-r}\equiv h_{l-1}\times10^{-(l-1)}\pmod D\),将 \(f_i,g_i\) 放进 \(h_i\times10^{-i}\) 对应桶里,每次查询桶里数的和即可。

若 \(\gcd(10,D)\neq1\),这时候 \(10\) 在\(\mod D\) 意义下没有逆元,不能用上述方法。

将 \(D\) 分解为 \(2^x5^yz\) 的形式。

那么同余方程可以分解为两个:

\(\begin{cases}h_r\equiv h_{l-1}\times10^{r-l+1}\pmod {2^x5^y}\\h_r\equiv h_{l-1}\times10^{r-l+1}\pmod {z}\end{cases}\)

如果要满足 \([l,r]\) 构成的十进制数字能整除 \(D\),必须同时满足上方两个式子。

由于 \(D\) 最大是 \(10^6\),也就是说 \(\max(x,y)\le20\),所以 \(r-l+1\ge20\) 的时候,\(h_{l-1}\times10^{r-l+1}\equiv0\pmod {2^x5^y}\)。

此时需要判断的条件就变成了:

\(\begin{cases}h_r\equiv 0\pmod {2^x5^y}\\h_r\equiv h_{l-1}\times10^{r-l+1}\pmod {z}\end{cases}\)

而 \(\gcd(10,z)=1\) ,套用 \(\gcd(10,D)=1\) 的方法就行了。

而当 \(r-l+1 < 20\) 的时候不能这么做,这部分暴力向前扫 \(20\) 个就行了。

代码写的有点繁。

点击查看代码
#include <bits/stdc++.h>
#define fr first
#define se second
#define Un unsigned
#define LL long long
#define pb push_back
#define pii pair<int,int>
#define pLi pair<LL,int>
#define pLL pair<LL,LL>
#define __ __int128
#define LD long double
#define VE vector<LL>
#define DB double
#define Ve vector<int>
//Keep your mind clear.
using namespace std;

const int N = 5e5+5,P = 1e9+7;
int f[N],g[N],F[N<<1],G[N<<1];
LL h[N],B[N],pw[N],H[N];

inline int mod(int x){return x >= P ? x-P : x < 0 ? x+P : x;}
void exgcd(int a,int b,int &x,int &y)
{
	if (!b) return (void)(x = 1,y = 0);
	exgcd(b,a%b,y,x),y -= a/b*x;
}

int main()
{
	freopen("division.in","r",stdin);
	freopen("division.out","w",stdout);
	ios::sync_with_stdio(0);
	string S;int D;cin >> S >> D;
	int n = S.size();S = " "+S;
	int K = D,x,y,C = 1;
	while (K%2 == 0) K /= 2,C *= 2;
	while (K%5 == 0) K /= 5,C *= 5;
	exgcd(10,K,x,y);pw[0] = 1;x = (x+K)%K;
	for (int i = 1;i <= n;i++) pw[i] = (pw[i-1]*x)%K;
	g[0] = B[0] = 1;
	int sum = 0;
	for (int i = 1;i <= n;i++)
	{
		if(i >= 20) F[H[i-20]] = mod(F[H[i-20]]+f[i-20]),G[H[i-20]] = mod(G[H[i-20]]+g[i-20]),sum = mod(sum+g[i-20]);
		h[i] = (h[i-1]*10+S[i]-'0')%D,B[i] = B[i-1]*10%D,H[i] = (h[i]*pw[i])%K;
		for (int j = i;j >= max(1,i-18);j--)
		{
			if ((h[i]-h[j-1]*B[i-j+1])%D) f[i] = mod(f[i]+g[j-1]);
			else g[i] = mod(g[i]+mod(f[j-1]+g[j-1]));
		}
		if (h[i]%C == 0) f[i] = mod(f[i]+mod(sum-G[H[i]])),g[i] = mod(g[i]+mod(F[H[i]]+G[H[i]]));
		else f[i] = mod(f[i]+sum);
	}
	cout << mod(f[n]+g[n]) << '\n';
	return 0;
}

C.矩阵删除

Sol1:

首先我们不考虑 “两个矩阵如果删除的元素位置不同,但最后得到的结果相同,我们认为是相同的” 这句话,可以得到一个朴素的 dp:\(f_{i,j}=\sum\limits_{j-k\leq l \leq j+k}f_{i-1,l}\),然后这个用前缀和优化转移即可做到 \(\mathcal O(nm)\)。

回过头来观察这句话对结果的影响,同一行一段相等的元素,移除它们的结果是一样的,这意味着我们会计算许多重复状态,考虑去除重复贡献。

我们发现对于第 \(i\) 行相邻的两个相同元素 \(j-1,j\),它们对应上一层的范围是这样的:

(红线为 \(j-1\),蓝线为 \(j\))

显然,上图中被白线框出来的线段被重复覆盖了,这一段为 \([j-k,j+k-1]\)。

我们新增一个数组 \(g\) 来记录每个元素可能会重复计算的贡献,那么 \(f\) 的转移方程就不难推出:

\[f_{i,j}=\sum\limits_{j-k\leq l \leq j+k}f_{i-1,l}-\sum\limits_{j-k+1\leq l \leq j+k}g_{i-1,l} \]

注意 \(g\) 的起始位置为 \(j-k+1\),因为左端点不会产生重复贡献。

根据 \(g\) 数组的定义和我们上面推出的式子,可以得到转移:

\[g_{i,j}=[a_{i,j}=a_{i,j-1}]\times (\sum\limits_{j-k\leq l\leq j+k-1}f_{i-1,l}-\sum\limits_{j-k+1\leq l\leq j+k-1}g_{i-1,l}) \]

答案即为 \(\sum\limits_{1\leq i\leq m} f_{n,i}-\sum\limits_{2\leq i\leq m} g_{n,i}\)。

然后这个也是从一段区间转移,前缀和优化即可,时间复杂度 \(\mathcal O(nm)\)。

Sol2:

若不考虑下一行,那么当前行一个连续段内每个位置都是等价的,唯一不同的是对下层决策区间的限制,而当前连续段对下层的决策区间是可以确定的,为 \([l-k,r+k]\),于是可以写出以下复杂度为 \(O(n^4)\) 的记搜:

点击查看代码
int D(int i,int l,int r)
{
	if (i > n) return 1;
	if (f[i].find(l*3000+r) != f[i].end()) return f[i][l*3000+r];
	int res = 0;
	for (int j = l;j <= r;j++)
	{
		int p = j;
		while(p < r && a[i][p+1] == a[i][p]) p++;
		res = mod(res+D(i+1,max(j-k,1),min(p+k,m))),j = p;
	}
	return f[i][l*3000+r] = res;
}

事实上这个东西在不特意卡的情况下下比 $O(n^3)$ 还要快,可以获得 70pts。 状态数 $O(n^3)$ 不太能优化了,于是从转移入手。发现一个连续段的贡献是独立的,而我们每次都 $O(n)$ 扫一遍太亏了,提前做个前缀和之后,对于所有被区间 $[l,r]$ 完全包含的连续段的贡献我们可以 $O(1)$ 求得(由于需要二分,所以是 $O(\log n)$)。对于两侧不完全的连续段记搜下去就好。时间复杂度 $O(n^3\log n)$,不特意卡跑的跟 $O(n^2\log n)$ 差不多快,可以通过。

D.路径查询

首先对于询问我们可以发现最后的答案一定是形如下图:

并且最大的边一定在左右两侧中的一侧。

那我们考虑 kruskal 从小到大加边,每次去合并连通块,因为我们是从小到大加的,所以最后答案一定会变成下图:

那么我们考虑合并的时候将出边和询问都合并到一个点上,使用启发式合并可以做到 \(O(n\log^2 n)\)。

标签:int,11.21,leq,times10,define,sum,mod
From: https://www.cnblogs.com/ZepX-D/p/18561285

相关文章

  • 24.11.21
    A怎么只有我一个写这种唐诗做法啊/kk当括号匹配时会对若干区间造成贡献。如果我们考虑每个右括号作为右端点统计贡献区间的话,左侧所有和它同一括号范围内(或最外层)的同层的左括号作为左端点和其构成一个贡献区间。举例子来说\(({\color{blue}(}))({\color{yellow}(}){\color{......
  • 11.21
    实验21:观察者模式本次实验属于模仿型实验,通过本次实验学生将掌握以下内容:1、理解观察者模式的动机,掌握该模式的结构;2、能够利用观察者模式解决实际问题。 [实验任务一]:股票提醒当股票的价格上涨或下降5%时,会通知持有该股票的股民,当股民听到价格上涨的消息时会买股票,当价......
  • PDF24 Creator(PDF工具箱) v11.21.0 绿色版
    PDF24Creator(PDF工具箱)v11.21.0绿色版 PDF24Creator是一款简单易用的多功能PDF创建工具。软件基于PDF打印机的原理而制作,用户使用这款软件可以帮助你轻松创建PDF文件。软件除了基本的PDF创建功能外,还有一个PDF转换功能,可以将其他格式的文件转换为磁盘PDF......
  • 11.21浏览一行信息
    <%@pagecontentType="text/html;charset=UTF-8"language="java"%><%@pageimport="java.sql.*"%><%@pageimport="javax.naming.*"%><%@pageimport="javax.*"%><html><body&g......
  • 11.21
    今天实现Mapper类LogOnMapperpackagecom.example.mapper;importcom.example.pojo.Department;importcom.example.pojo.Staff;importorg.apache.ibatis.annotations.*;importjava.time.LocalDate;importjava.util.List;@MapperpublicinterfaceLogONMapper{......
  • 11.21
    1.用结构体存放如下表中的数据,然后输出每个人的姓名和实发工资(实发工资=基本工资+浮动工资-支出)姓名基本工资浮动工资支出Tom1240.00800.0075.00Lucy1360.00900.0050.00Jack1560.001000.0080.00程序代码:#inclu......
  • 11.21
    今日学习内容<%@pageimport="java.sql.*"%><%@pageimport="java.sql.DriverManager"%><%--CreatedbyIntelliJIDEA.TochangethistemplateuseFile|Settings|FileTemplates.--%><%@pagecontentType="text/htm......
  • 11.21
    Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程。......
  • 11.21学习小结 //LCA
    倍增求LCA参考博文:https://www.cnblogs.com/hulean/p/11144059.html参考博文:https://www.cnblogs.com/jvxie/p/4854719.html·记录每个点的深度,和往前2^i的祖先。·先把两个点提到同一高度,再统一开始跳。不可以直接跳到相同祖先处,因为可能是LCA的祖先·裸板子:洛谷P3379wa......
  • 11.21b级请假审批实现了
           <!DOCTYPEhtml><htmlxmlns:th="http://www.thymeleaf.org"><head><metacharset="UTF-8"><metaname="renderer"content="webkit"><metahttp-equiv=......