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

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. Canvas图形编辑器-数据结构与History(undo/redo)

    Canvas图形编辑器-数据结构与History(undo/redo) 这是作为 社区老给我推Canvas,于是我也学习Canvas做了个简历编辑器 的后续内容,主要是介绍了对数据结构的设计以及His ...

  2. 6980. 【2021.02.03冬令营模拟】你的世界(world) Another Solution

    Problem Description Input 从文件 world.in 中读入数据. Output 输出到文件 world.out 中. 输出共 T 行,第 i 行表示第 i 组测试数据的答案, ...

  3. 05_理解MVVM模型

    总结: MVVM模型:         1.M:模型(Model):data中是的数据         2.V:视图(View):模板代码         3.VM:视图模型(ViewModel):V ...

  4. 终于要跟大家见面了,Flink 面试指南

    面试,一个令人大多数同学头疼的问题,要么成功进入心仪公司,要么沮丧与其失之交臂.但是,如果能在面试前就能知道面试官将会问的问题,然后可以好好提前准备,这种感觉是不是特别棒? 之前社区帮大家汇总了目前 ...

  5. Apsara Stack 技术百科 | 可运营的行业云,让云上资源跑起来

    ​简介:企业级云管理平台,如何打造千人千面的个性化体验,从应用.云资源.硬件等进行全局智能优化,实现资源配置的最佳配比,构建精细化运营能力? ​ 距离第一例新冠疫情病例的发现,不知不觉中已经过去两年, ...

  6. 谈谈JVM内部锁升级过程

    简介: 对象在内存中的内存布局是什么样的?如何描述synchronized和ReentrantLock的底层实现和重入的底层原理?为什么AQS底层是CAS+volatile?锁的四种状态和锁升级过程应 ...

  7. [FAQ] JS 实现暂停(睡眠) Sleep 与 倒计时 ?

    想要暂停/睡眠一秒,可以参考使用以下方式: async () => { await (new Promise((resolve) => setTimeout(resolve, 1000)) ...

  8. [PHP] 自定义 laravel/passport 的误区讲解

    Passport 的 Client 模型对应用户是默认的 User 模型.使用的 guards 是 api. 如果你发现自定义 passport 时总是调试不成功,那么很有可能是以下原因. /** * ...

  9. 记录一个HttpClient超时连接配置不生效的问题排查过程

    现象 首先有一个被服务由于内存有限,导致巨卡.导致调用他的服务出现线程阻塞.jstack打印线程池如下所示: 开始排查解决问题 第一步:检查代码看是否超时设置是否正确,因为感觉超时设置正确不可能阻塞. ...

  10. AtCoder Beginner Contest 333

    总结 人生第一次掉rating 各种降智操作 A 水题 B 逆天操作 WA了3发 第三次交的时候以为过了,等到切完E发现怎么B还没过( #include<bits/stdc++.h> us ...