zoukankan      html  css  js  c++  java
  • YAOI Round #3 题解

    前言

    比赛链接:

    Div.1 : http://47.110.12.131:9016/contest/7

    Div.2 : http://47.110.12.131:9016/contest/8

    Div.2——四月是你的谎言

    下面是 Div.2 的题解。

    A. 若能绽放光芒

    首先讲一个 (Theta(n^3)) 的暴力:

    枚举区间 ([l,r]),这里已经有 (Theta(n^2)) 的时间复杂度了。

    然后我们考虑怎么找到这段区间对应的最长公共“子序列”。

    这个贪心一下,找到从左到右的第一个下一个字母,(Theta(n)) 匹配即可,这里有 (Theta(n)) 的时间复杂度。

    故总的时间复杂度是 (Theta(n^3))

    接着讲一下 (Theta(n^2)) 的做法:

    实际上你会发现上面那个是增量构造,对此我们可以优化。

    考虑固定左端点,右移右端点,这样可以省去一维的复杂度。

    于是就优化成了 (Theta(n^2)) 的时间复杂度,即可通过本题。

    for(Re int i=1;i<=n;i++)
    {
    	int k=0;
    	for(Re int j=i;j<=n;j++)
    	{
    		while(k<=m&&b[k]!=a[j])
    		{
    			k++;
    		}
    		if(k>m)
    		{
    			ans=min(ans,j-i+1);
    			break;
    		}
    		k++;
    	}
    }
    

    B. 七色交响曲

    对于 (30\%) 的数据,我们考虑对 (n) 个物品枚举它们属于的容器情况即可,时间复杂度大约为 (Theta(n!))

    对于 (60\%) 的数据,我们换个更优秀的搜索策略,并加上记忆化

    考虑 ([l,r]) 区间最优怎么算,我们枚举它中间的断点,把这个区间分成两块处理,也就是所谓的分治

    它的思想就是来源于搜索,于是我们考虑在分治过程中加上记忆化数组。

    这样,它的时间复杂度为 (Theta(n^3))

    对于 (100\%) 的数据,我们考虑这样一个动态规划想法:

    如果想到了上面的记忆化搜索思想,那这题的动态规划思路应该还是很好想的。

    (f[i]) 表示将 (1)(i) 的物品都放入容器中的最小费用。

    我们考虑枚举一个 (j) 来进行转移,具体状态转移方程如下:

    [f[i]=min_{0leq j<i}{f[j]+(sum_{k=j+1}^{i}l[k]+i-j-1-p)^{2}} ]

    (l) 的前缀和数组为 (s) ,即 (s[i]=sumlimits_{k=1}^{i}l[k]) ,那么方程就变为如下形态:

    [f[i]=min_{0leq j<i}{f[j]+(s[i]-s[j]+i-j-1-p)^{2}} ]

    此时我们暴力去做,时间复杂度为 (O(n^2)),即可通过本题。

    memset(dp,127/3,sizeof dp);
    dp[0]=0;
    for(Re int i=1;i<=n;i++)
    {
    	for(Re int j=0;j<i;j++)
    	{
    		dp[i]=min(dp[i],dp[j]+(s[i]-s[j]+i-j-1-p)*(s[i]-s[j]+i-j-1-p));
    	}
    }
    

    C. 闪耀

    为了方便起见,下面设题目中的两人为甲、乙。

    设投票记录用 (m+n) 元有序组 ((a_1,a_2,...,a_{m+n})) 表示。

    当第 (1leq kleq m+n) 次唱票时,如果选票为甲,则 (a_k=1),否则 (a_k=-1)

    (b_k=sumlimits_{i=1}^{k}a_i),然后考虑用折线法来求解。

    从左到右连接以下格点:((1,b_1),(2,b_2),...,(m+n,b_{m+n})),得到一条 (m+n-1) 节的折线。

    因为甲的票数一直领先,所以 (forall k,b_k>0),且 (b_1=1,b_{m+n}=m-n)

    换句话说,这是一条连接 ((1,1))((m+n,m-n)) 且与 (x) 轴没有交点的折线。

    由简单的数学知识可知:这种折线数目为 (egin{aligned} ext{C}_{m+n-1}^{m-1}- ext{C}_{m+n-1}^{m}=frac{m-n}{m+n} ext{C}_{m+n}^{m} end{aligned})

    直接预处理逆元后输出即可,时间复杂度 (Theta(n))

    int ans=1;
    ans=(1ll*ans*inv[m+n])%mod;
    ans=(1ll*ans*(m-n))%mod;
    for(Re int i=1;i<=m;i++)
    {
    	ans=(1ll*ans*inv[i])%mod;
    	ans=(1ll*ans*(m+n-i+1))%mod;
    }
    

    D. 橘黄

    搜索即可,你们不是刚刚学了搜索吗???

    直接枚举每种情况,然后算答案即可,时间复杂度约为 (Theta(n!))

    由于这种做法比较简单,更优的做法代码放在 Div.2 的 D 题中。

    E. 爱之忧伤

    对于 (20\%) 的数据,我们考虑枚举两个点 (i,j) 后暴力跳 LCA 来求 (f(i,j)),时间复杂度为 (Theta(n^3))

    对于 (50\%) 的数据,我们在跳 LCA 的时候考虑 倍增/重链剖分/Tarjan 来优化它,时间复杂度可以做到 (Theta(n^2log n))

    对于 (100\%) 的数据,我们换一个思路:

    对于每个点,看看它是哪些点对的 LCA,然后只要考虑每个点这样的贡献,最后把它们求和。

    具体来说,我们枚举一个 (i),记录下以 (i) 为根的子树大小,然后直接用这个计算即可。

    时间复杂度为 (Theta(n))

    inline void dfs(int u,int f)
    {
    	sz[u]=1;
    	for(Re int i=0;i<T[u].size();i++)
    	{
    		int v=T[u][i];
    		if(v==f) continue;
    		dfs(v,u);
    		ans=(ans+a[u]*(1ll*sz[u]*sz[v]%mod)%mod)%mod;
    		sz[u]+=sz[v];
    	}
    }
    

    Div.1——末日三问

    下面是 Div.1 的题解。

    A. Always in my heart

    我们考虑把每个位置连一条指向下一个 ( ext{a})( ext{z}) 的边,这样形成的图叫作子序列自动机

    所以用 (Theta(n |Sigma|)) 的时间建出来,再用 (Theta(n)) 的时间枚举一遍,然后就做完了。

    f[0][0]=0;
    for(Re int i=0;i<=m;i++)
    {
    	for(Re int k=0;k<26;k++)
    	{
    		if(pntB[i][k]!=-1)
    		{
    			for(Re int j=0;j<=n;j++)
    			{
    				if(pntA[j][k]!=-1)
    				{
    					f[pntB[i][k]][pntA[j][k]]=min(f[pntB[i][k]][pntA[j][k]],f[i][j]+1);
    				} 
    			}
    		} 
    		else 
    		{
    			for(Re int j=0;j<=n;j++)
    			{
    				if(pntA[j][k]!=-1)
    				{
    					ans=min(ans,f[i][j]+1);
    				}
    			}
    		}
    	}
    }
    

    B. Ever be my love

    我们考虑把 Div.3 的那个式子优化成 (Theta(n)),而这要用到斜率优化的内容,可以学一学,详见:

    https://www.cnblogs.com/kebingyi/p/14157680.html

    C. Chtholly Nota Seniorious

    本题与 Div.3 的 C 题类似,读者可不妨自行推导出这样的式子:

    [ans=frac{m}{m+n} ext{C}_{m+2n-1}^{n} ]

    同样,我们直接求解即可。

    int ans=1;
    ans=(1ll*ans*inv[m+n])%mod;
    ans=(1ll*ans*m)%mod;
    for(Re int i=1;i<=n;i++)
    {
    	ans=(1ll*ans*inv[i])%mod;
    	ans=(1ll*ans*(m+n+n-i))%mod;
    }
    

    D. Scarborough Fair

    很妙的!

    这个搜索类似于上面 Div.3 的 B 题中 (60\%) 部分分的形式。

    我们以几乎同样的思路再做一遍就不难得出正解,具体的由场切的 chenxulei 大佬来讲解吧!

    其实这个题是 IOI2020 国家集训队作业的原题,有能力的同学可以考虑刷一刷这个。

    LL dfs(int L,int R,LL x,LL y)
    {
    	if(L>R) return 0;
    	LL ret=1e17;
    	for(Re int i=L;i<=R;i++)
    	{
    		ret=min(ret,dfs(L,i-1,x,x+y)+dfs(i+1,R,x+y,y)+a[i]*(x+y));
    	}
    	return ret;
    }
    

    E. 最幸福的女孩

    大家知道那个 (O(nln n)) 求数论函数的技巧吗?

    不知道的话可以学学,看如下标程:

    for (Re int i = 1, j; i < maxn; i++)
    	for (Re int j = 1; j * i < maxn; j++)
    		(f[i * j] += g[i] * 1ll * phi[j] % mod * mu[pi[i]] % mod) %= mod;
    

    这么做看着是 (O(n^2)) 的,其实是 (O(nln n)) 的,至于为什么就自己去学学吧……

    然后前缀和一下:

    for (Re int i = 1; i < maxn; i++) (f[i] += f[i - 1]) %= mod;
    

    这样就可以 (O(1)) 查询了。

  • 相关阅读:
    MyEclipse优化设置(最详细版本)
    报错:java.net.bindexception: address already in use: jvm_bind:8080
    java.net.BindException: Address already in use: JVM_Bind
    MyEclipse总是quick update解决办法
    【EJB学习笔记】——EJB开发环境搭建(Eclipse集成JBoss)
    对EJB2.1几种接口的认识
    免安装PostgreSQL启动服务及创建数据库
    git使用教程5-pycharm修改代码后提交到代码仓库
    git使用教程4-pycharm拉取git仓库项目代码
    git使用教程3-解决github网页打开慢的问题
  • 原文地址:https://www.cnblogs.com/kebingyi/p/14247064.html
Copyright © 2011-2022 走看看