你的败因只有一个,就是与我为敌。 ­

T1 卷

解题思路

乍一看,简单的树形 DP 。

后来一看数据范围,发现事实并非如此。(\((10^9)^{2\times 10^5}\)????)

毕竟取 \(\bmod\) 之后的值就可以直接比较大小了。。

第一感觉是高精(当然可以做, 太虚真人 就把这个题用高精干掉了)。

后来发现其实 DP 的值都只是乘积的形式,所以说考虑 \(log\) 运算。

这样就可以完美的把乘运算变为加运算了。

然后我们开两个 DP 数组,一个用来计算 \(log\) 运算,一个用来计算取 \(\bmod\) 之后的值。

不可以用 \(log\) 的运算答案直接作为指数(还有一些奇怪的操作)算答案(反正我是写挂了)

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Pass"<<endl
#define double long double
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=2e5+10,mod=1e9+7;
const double base=log(mod),eps=1e-13,mo=1e9+7;
double f[N][2];
int n,s[N],g[N][2];
int tot=1,head[N],nxt[N<<1],ver[N<<1];
void add_edge(int x,int y)
{
ver[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
}
double cl(int x)
{
return log(x)/base;
}
void dfs(int x,int fat)
{
f[x][0]=cl(1); f[x][1]=cl(s[x]);
g[x][0]=1; g[x][1]=s[x]%mod;
for(int i=head[x];i;i=nxt[i])
{
int to=ver[i];
if(to==fat) continue;
dfs(to,x);
if(f[to][0]>f[to][1]) g[x][0]=g[to][0]*g[x][0]%mod;
else g[x][0]=g[to][1]*g[x][0]%mod;
f[x][0]=max(f[to][0],f[to][1])+f[x][0];
f[x][1]=f[to][0]+f[x][1];
g[x][1]=g[to][0]*g[x][1]%mod;
}
}
signed main()
{
n=read();
for(int i=1;i<=n;i++)
s[i]=read();
for(int i=1,x,y;i<n;i++)
{
x=read(); y=read();
add_edge(x,y);
add_edge(y,x);
}
dfs(1,0);
if(f[1][0]>f[1][1]) printf("%lld",g[1][0]);
else printf("%lld",g[1][1]);
return 0;
}

T2 简单题

解题思路

首先不难发现数都是分为类似于 \(i,i\times 2^1,i\times 2^2...i\times 2^k\) 这样的形式的,在这里我们姑且把它们视作 链 。

那么对于这些链而言,开头都是 奇数 ,并且链长都是 \(log\) 级别的。

对于每一条链一定是间隔着选,分成固定的两部分。

并且对于长度为偶数的链而言两部分的长度就都是链长的一半。

对于奇数链而言就可以分成两部分,只不过一部分比另一部分多了 1 个数。

然后发现可以组成的集合 A 的大小一定是大于 所有偶数链长度的一半加上所有奇数链较短的一部分所组成的集合大小的,假设最小集合大小为 l 。

每个偶数链的直接贡献是 2 ,剩下的就是 从所有的奇数链中选出 \(m-l\) 个直接卢卡斯。

直接枚举每一种开头的奇数显然是不行的。

我们换一种枚举方式,枚举链的长度,计算长度为它的数量,记为 cnt 。

那么 \(cnt_i=\lfloor\dfrac{\lfloor\frac{n}{2^i}+1\rfloor}{2}\rfloor-cnt_{i+1}\)

然后就可以 \(\mathcal{O(logn)}\) 初始化 对于每一个询问 \(\mathcal{O(1)}\) 求解了。

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Pass"<<endl
#define double long double
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=5e3+10,M=1e7+10,mod=1e7+19,Lg=70;
int n,m,q,lg,l=0,f[N],cnt[N],all,tot;
int jc[mod+10],inv[mod+10],p2[Lg];
int ys(int x,int y)
{
if(x>y) return 0;
return jc[y]*inv[x]%mod*inv[y-x]%mod;
}
int C(int x,int y)
{
if(!x||x==y) return 1;
if(x>y) return 0;
return ys(x%mod,y%mod)*C(x/mod,y/mod)%mod;
}
int ksm(int x,int y)
{
int temp=1;
while(y)
{
if(y&1) temp=temp*x%mod;
x=x*x%mod;
y>>=1;
}
return temp%mod;
}
signed main()
{
n=read(); q=read(); lg=log2(n)+1;
jc[0]=inv[0]=p2[0]=1;
for(int i=1;i<mod;i++) jc[i]=jc[i-1]*i%mod;
inv[mod-1]=ksm(jc[mod-1],mod-2);
for(int i=mod-2;i>=1;i--) inv[i]=inv[i+1]*(i+1)%mod;
for(int i=1;i<=lg;i++) p2[i]=p2[i-1]*2;
for(int i=0;i<=lg;i++) cnt[i]=(n/p2[i]+1)/2;
for(int i=0;i<=lg;i++) cnt[i]-=cnt[i+1];
for(int i=0;i<=lg;i++)
if((i+1)&1)
tot+=cnt[i];
for(int i=1;i<=lg;i++)
l+=cnt[i]*((i+1)/2);
all=(n+1)>>1;
int base=ksm(2,all-tot)%mod;
while(q--)
{
m=read();
if(m<l) printf("0\n");
else printf("%lld\n",base*C(m-l,tot)%mod);
}
return 0;
}

T3 粉丝

解题思路

有两种计算划分数的 DP

\(f_{i,j}\)表示当前 DP 到数字 i 也就是最大的数字为 i ,总和为 j 的方案数。

转移方程就是:\(f_{i,j}=f_{i-1,j}+f_{i-1,j-k}(k\in[1,i])\)

\(g_{i,j}\)表示当前分成了 i 个数字,总和为 j 的方案数

转移方程就是:\(g_{i,j}=g_{i-1,j}+g_{i,j-i}\)。

注意上述的所有方程都暂时不考虑起始为 \([x,y]\) 的限制。

我们就可以固定下界,上界直接设为 n ,然后就类似与求了一个后缀,减一下就好了。

这两个 dp 分别使用都是 \(\mathcal{O(n^2)}\) 的,但是假设我们令\(B=\sqrt{n}\) ,把所有 \(\le B\) 的数字都拿出来使用 f 的那个 dp。

那么剩下的数字都必然 \(>B\) ,因此最多被划分成 \(\dfrac{n}{B}\) 个数字,此时使用 g 来 dp。

最后合并两个 DP 的值,复杂度为 \(O(n\sqrt{n})\)

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Pass"<<endl
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=1e5+10;
int ans,n,mod,l,r,f[N],g[N],cnt[N];
int work(int x)
{
int ans=0,ending=max(x,(int)sqrt(n));
memset(f,0,sizeof(f));
memset(g,0,sizeof(g));
memset(cnt,0,sizeof(cnt));
f[0]=g[0]=cnt[0]=1;
for(int i=x;i<ending;i++)
for(int j=0;j<=n-i;j++)
f[i+j]=(f[i+j]+f[j])%mod;
for(int i=1;i<=n/ending;i++)
{
for(int j=0;j<=n-i*ending-i;j++)
g[i+j]=(g[i+j]+g[j])%mod;
for(int j=0;j<=n-i*ending;j++)
cnt[j+i*ending]=(cnt[j+i*ending]+g[j])%mod;
}
for(int i=0;i<=n;i++)
ans=(ans+f[i]*cnt[n-i]%mod)%mod;
return ans;
}
signed main()
{
l=read(); r=read(); n=read(); mod=read();
printf("%lld",((l<=n?work(l):0)-(r<n?work(r+1):0)+mod)%mod);
return 0;
}

T4 字符串

解题思路

Manacher+KMP

首先对于两端相等的部分是一定要选上的。

然后对于剩下的部分可以看做 \(B+D\) 或者 \(A+C\) ,正反做两遍就好了。

先是对于原串跑一边 Manacher 搞出每个位置的最大的回文半径。

接下来利用 KMP 的 next 数组求出字符串的 border 。(这里需要把原串反转一下在放到最后)

答案就变成了对于原串的每一个字符而言,自身最大的回文半径再加上两倍的 next 数组,也就是我们所求的 border 在整个字符串的两端各放一个。

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Pass"<<endl
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=5e6+10;
char s[N],km[N<<1],ma[N<<1];
int n,ans,cntk,cntm,tot,p[N<<1],nxt[N<<1],mx[N<<1];
void Manacher()
{
memset(p,0,sizeof(p));
ma[cntm=0]='~'; ma[++cntm]='|';
for(int i=1;i<=n;i++)
{
ma[++cntm]=s[i];
ma[++cntm]='|';
}
for(int i=1,r=0,mid=0;i<=cntm;i++)
{
if(i<=r) p[i]=min(p[mid*2-i],r-i+1);
while(ma[i-p[i]]==ma[i+p[i]]) p[i]++;
if(p[i]+i-1>=r) r=p[i]+i-1,mid=i;
}
}
void KMP()
{
cntk=n;
memcpy(km+1,s+1,sizeof(char)*n);
km[++cntk]='$';
for(int i=n;i>=1;i--)
km[++cntk]=s[i];
memset(nxt,0,sizeof(nxt));
memset(mx,0,sizeof(mx));
for(int i=cntk-1,j=0;i>=1;i--)
{
while(j>0&&km[i]!=km[cntk-j]) j=nxt[j];
if(km[i]==km[cntk-j]) j++;
nxt[i]=j;
}
for(int i=n;i>=1;i--)
mx[i]=max(mx[i+1],nxt[i]);
}
void solve()
{
Manacher(); KMP();
for(int i=1;i<=cntm;i++)
{
int l=(i-p[i])>>1,r=(i+p[i])>>1;
if(nxt[r]<=l) ans=max(ans,p[i]+2*nxt[r]-1);
if(mx[r]>=l) ans=max(ans,p[i]+2*l-1);
}
}
signed main()
{
scanf("%s",s+1);
n=strlen(s+1);
for(int i=1;i<=n/2;i++)
if(s[i]==s[n-i+1]) tot++;
else break;
if(tot>=n/2){printf("%lld",n);return 0;}
n-=2*tot;
for(int i=1;i<=n;i++)
s[i]=s[i+tot];
solve();reverse(s+1,s+n+1);solve();
printf("%lld",ans+2*tot);
return 0;
}

8.17考试总结(NOIP模拟42)[卷·简单题·粉丝·字符串]的更多相关文章

  1. 6.17考试总结(NOIP模拟8)[星际旅行·砍树·超级树·求和]

    6.17考试总结(NOIP模拟8) 背景 考得不咋样,有一个非常遗憾的地方:最后一题少取膜了,\(100pts->40pts\),改了这么多年的错还是头一回看见以下的情景... T1星际旅行 前 ...

  2. 2021.9.17考试总结[NOIP模拟55]

    有的考试表面上自称NOIP模拟,背地里却是绍兴一中NOI模拟 吓得我直接文件打错 T1 Skip 设状态$f_i$为最后一次选$i$在$i$时的最优解.有$f_i=max_{j<i}[f_j+a ...

  3. [考试总结]noip模拟42

    开始给了一个简单的题目,但我还是没有珍惜. 一个简简单单的树形 \(dp\),然而因为取模却不知道该如何比较大小.. 其实可以取 \(log\),然后我就梦中惊坐起,然后想到了魔法少女lbw 淦 然后 ...

  4. 2021.6.17考试总结[NOIP模拟8]

    T1 星际旅行 其实就是求两条只走一遍的边的方案数. 考场上第一眼就感觉不可做,后来画了几个图,发现好像只要两个边是相连的就可以只走一遍,居然还真拿了30.. 其实是一道欧拉路的题,把每条非自环的边看 ...

  5. 5.23考试总结(NOIP模拟2)

    5.23考试总结(NOIP模拟2) 洛谷题单 看第一题第一眼,不好打呀;看第一题样例又一眼,诶,我直接一手小阶乘走人 然后就急忙去干T2T3了 后来考完一看,只有\(T1\)骗到了\(15pts\)[ ...

  6. 5.22考试总结(NOIP模拟1)

    5.22考试总结(NOIP模拟1) 改题记录 T1 序列 题解 暴力思路很好想,分数也很好想\(QAQ\) (反正我只拿了5pts) 正解的话: 先用欧拉筛把1-n的素数筛出来 void get_Pr ...

  7. Noip模拟42 2021.8.17

    T1 卷 一看跟没有上司的舞会一样,直接敲了然后试个自己造的样例对了就跑了... 然而把它想简单了,乘积取模,还能比大小吗????? 显然不能 所以直接让对数的加和跟着$dp$直接一起跑,比大小的都用 ...

  8. [考试总结]noip模拟23

    因为考试过多,所以学校的博客就暂时咕掉了,放到家里来写 不过话说,vscode的markdown编辑器还是真的很好用 先把 \(noip\) 模拟 \(23\) 的总结写了吧.. 俗话说:" ...

  9. 2021.8.12考试总结[NOIP模拟37]

    T1 数列 考场上切掉的简单题. $a$,$b$与数列中数的正负值对答案无关.全当作正数计算即可. $exgcd$解未知数系数为$a$,$b$,加和为$gcd(a,b)$的不定方程组,再枚举每个数.如 ...

  10. noip模拟42

    A. 卷 发现乘积足以爆 \(long\) \(long\),但是数据随机,可以略忽略精度问题 一个快速降低数的级别的方法是取对数,由于有性质 \(log(x * y)=logx+logy\),合并时 ...

随机推荐

  1. docker 应用篇————swarm[二十]

    前言 简单介绍一下swarm. 正文 前提,docker 安装. 有3台机器,全部按照了docker. 现在开始搭建集群. 首先需要初始化: 然后需要注入: 注入之后,那么需要就是启动节点加入进来,那 ...

  2. jenkins 持续集成和交付 —— git hook(七)

    前言 这个hook的意思叫做钩子哈,前端听得多. 正文 好吧,这个git hook 有什么用呢? 前面说了一个轮询SCM这个东西呢,我是真的觉得这东西没啥用,经常扫描仓储算怎么回事呢? 但是如果主动通 ...

  3. 【pytorch学习】之概率

    6 概率 简单地说,机器学习就是做出预测.根据病人的临床病史,我们可能想预测他们在下一年心脏病发作的概率.在飞机喷气发动机的异常检测中,我们想要评估一组发动机读数为正常运行情况的概率有多大.在强化学习 ...

  4. 耗时又繁重的SQL诊断优化,以后就都交给数据库自治服务DAS吧!

    在我们业务系统中,数据库越来越扮演着举足轻重的角色. 和其它公司一样,在阿里巴巴业务场景下,大部分业务跟数据库有着非常紧密的关系,数据库一个微小的抖动都有可能对业务造成非常大的影响, 如何让数据库更稳 ...

  5. 参与 Apache 顶级开源项目的 N 种方式,Apache Dubbo Samples SIG 成立!

    简介: 一说到参与开源项目贡献,一般大家的反应都是代码级别的贡献,总觉得我的代码被社区合并了,我才算一个贡献者,这是一个常见的错误认知.其实,在一个开源社区中有非常多的角色是 non-code con ...

  6. LlamaIndex 探索视频系列

    如果您喜欢通过视频学习,现在正是查看我们的"探索 LlamaIndex"系列的好时机.否则,我们建议您继续阅读"理解 LlamaIndex"教程. 自下而上开发 ...

  7. [FAQ] gormV2 Too many connections

    gormV2 中不再有v1的 db.Close() 方法. 取而代之的 close 方式是如下: sqlDB, err := DB.DB() sqlDB.Close() https://github. ...

  8. 2019-11-21-win10-uwp-在-Grid-接收键盘消息

    title author date CreateTime categories win10 uwp 在 Grid 接收键盘消息 lindexi 2019-11-21 08:51:51 +0800 20 ...

  9. Django之ORM操作Mysql

    一.单表操作 # 单表查询操作基本方法 class BookList(models.Model): title = models.CharField(max_length=32) price = mo ...

  10. 有意思!一个关于 Spring 历史的在线小游戏

    发现 Spring One 的官网上有个好玩的彩蛋,分享给大家! 进到Spring One的官网,可以看到右下角有个类似马里奥游戏中的金币图标. 点击该金币之后,会打开一个新的页面,进入下面这样一个名 ...