2019.10.22 csp-s模拟测试82 反思总结
重来重来,刚刚就当什么都没发生
今天的题属实有些迷惑,各种意义上…总之都很有难度吧。不满归不满,这套题的确不是什么没有意义的题目。
为了考验自己的学习能力记忆力,决定不写题解,扔个代码完事了
其实是懒得写一大堆式子的推理以及想表示一下对出题人的敬意
你就不怕你到时候回来看一脸懵逼吗
T1:
#include<iostream>
#include<cstdio>
using namespace std;
int t,mod=,mod1=;
long long n;
int main()
{
scanf("%d",&t);
long long num=,x=;
while(mod1){
if(mod1&)num=num*x%mod;
x=x*x%mod;
mod1>>=;
}
while(t--){
scanf("%lld",&n);
n%=mod;
printf("%lld\n",(n*n%mod-)*num%mod);
}
return ;
}
T2:
这题考场上出70分思路挺快的,大概20min或者更少,连带读完三道题的时间…这个思路本质上也是推导正解的中间过程
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1e5+;
int n,len,nxt[*N],lons;
long long ans,num1[*N],num2[*N];
char s[*N],c[*N],a[*N],ss[*N];
void kmp1(int lon){
strcpy(a+lon+,s+);
a[lon+]='.';
int lens=strlen(a+);
for(int i=;i<=lens;i++)nxt[i]=;
for(int i=;i<=lens;i++){
int j=nxt[i-];
while(j&&a[j+]!=a[i])j=nxt[j];
if(a[j+]==a[i])nxt[i]=j+;
if(nxt[i]==lon)num1[i-*lon]++;
}
}
void kmp2(int lon){
strcpy(a+lon+,s+);
a[lon+]='.';
int lens=strlen(a+);
for(int i=;i<=lens;i++)nxt[i]=;
for(int i=;i<=lens;i++){
int j=nxt[i-];
while(j&&a[j+]!=a[i])j=nxt[j];
if(a[j+]==a[i])nxt[i]=j+;
if(nxt[i]==lon)num2[i-lon-]++;
}
}
int main()
{
scanf("%s",s+);
lons=strlen(s+);
scanf("%d",&n);
for(int i=;i<=n;i++){
scanf("%s",c+);
len=strlen(c+);
for(int j=;j<=len;j++){
strcpy(a+,c+);
strcpy(a+j+,ss+);
kmp1(j);
strcpy(a+,c+j);
strcpy(a+len-j+,ss+);
kmp2(len-j+);
}
}
for(int i=;i<=lons;i++){
ans+=num1[i]*num2[i-];
}
printf("%lld\n",ans);
return ;
}
考场70pts
这个70分的做法是,读入一个字符串以后,暴力地扫出它的所有前后缀,对每一个前后缀在s串上跑一下kmp。如果是后缀,就在s串匹配成功的位置让计数器cnt2++。如果是前缀,就在s串匹配成功的子串的开始位置让计数器cnt1++。
最后扫一遍计数器数组(到s串的长度),ans+=cnt2i*cnt1i+1。
应该是正解里最基础的那部分吧。
能想到正解的一部分对于一个菜鸡来说太不容易了赶紧详细写一下【?】
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1e5+,p=,mod=;
int n,len,cnt1=,cnt2=,lens;
char s[*N],c[*N];
int tree1[*N][],tree2[*N][];
unsigned long long hash1[*N],hash2[*N],ks[*N];
long long ans;
struct node{
int m;
#define m 1500007
int head[][m+],Next[][*N],tot[];
long long siz[][*N];
unsigned long long ver[][*N];
void ins(unsigned long long has,int opt,long long sum){
unsigned long long x=has%m;
for(int i=head[opt][x];i;i=Next[opt][i]){
if(has==ver[opt][i]){
siz[opt][i]+=sum;
return;
}
}
ver[opt][++tot[opt]]=has,siz[opt][tot[opt]]=sum,Next[opt][tot[opt]]=head[opt][x],head[opt][x]=tot[opt];
return;
}
long long get(unsigned long long has,int opt){
unsigned long long x=has%m;
for(int i=head[opt][x];i;i=Next[opt][i]){
if(has==ver[opt][i]){
return siz[opt][i];
}
}
return ;
}
}h;
void insert(){
int now=;
unsigned long long has=;
for(int i=;i<=len;i++){//前缀
has=has*p+c[i];
if(!tree1[now][c[i]-'a'])tree1[now][c[i]-'a']=++cnt1;
h.ins(has,,);
now=tree1[now][c[i]-'a'];
}
now=,has=;
for(int i=len;i>=;i--){//后缀
has=has*p+c[i];
if(!tree2[now][c[i]-'a'])tree2[now][c[i]-'a']=++cnt2;
h.ins(has,,);
now=tree2[now][c[i]-'a'];
}
}
void dfs1(int now,unsigned long long has){
for(int i=;i<;i++){
if(tree1[now][i]){
long long val=has*p+i+'a';
long long sum=h.get(has,);
h.ins(val,,sum);
dfs1(tree1[now][i],val);
}
}
}
void dfs2(int now,unsigned long long has){
for(int i=;i<;i++){
if(tree2[now][i]){
long long val=has*p+i+'a';
long long sum=h.get(has,);
h.ins(val,,sum);
dfs2(tree2[now][i],val);
}
}
}
long long work(int x){
int l=,r=x,ans1=,ans2=;
while(l<=r){//后缀
int mid=(l+r)/;
unsigned long long val=hash2[mid]-hash2[x+]*ks[x-mid+];
long long sum=h.get(val,);
if(sum){
ans2=sum;
r=mid-;
}
else l=mid+;
}
l=x+,r=lens;
while(l<=r){//后缀
int mid=(l+r)/;
unsigned long long val=hash1[mid]-hash1[x]*ks[mid-x];
long long sum=h.get(val,);
if(sum){
ans1=sum;
l=mid+;
}
else r=mid-;
}
return 1ll*ans1*ans2;
}
int main()
{
scanf("%s",s+);
lens=strlen(s+);
ks[]=;
for(int i=;i<=lens;i++){
hash1[i]=hash1[i-]*p+s[i];
ks[i]=ks[i-]*p;
}
for(int i=lens;i>=;i--){
hash2[i]=hash2[i+]*p+s[i];
}
scanf("%d",&n);
for(int i=;i<=n;i++){
scanf("%s",c+);
len=strlen(c+);
insert();
}
dfs1(,);
dfs2(,);
for(int i=;i<lens;i++){
ans+=work(i);
}
printf("%lld\n",ans);
return ;
}
很神奇的思路转化:让一个中间点前面衔接的最长后缀代表所有更靠近中间点的后缀,记录一个前缀和。因为不用考虑每个前后缀具体的位置,只要存在包含它的更长前后缀就一定能同时对答案产生贡献,所以可以利用trie树来统计一下前缀和。就trie树的操作过程来说,的确非常适合统计数量的前缀和信息。用hash映射所有存在的前后缀,在每个中间点记录答案的时候二分这个最长前后缀。相当于用hash和trie树替代掉了原本一次次跑kmp匹配的过程,非常优秀。
关于我为什么这么生气的原因,这题在hash上搞幺蛾子?嗯?
大概率是我菜吧
记一下要点:巩固一下ull自然溢出,以及哈希表
哈希表本质是利用关键字的分类(散列函数映射)来加速查询
T3:
#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;
const int mod=3e5+;
int t;
ll n,m,k,ans,rec[mod+],inv[mod+],minn;
ll ksm(ll x,int k){
ll num=;
while(k){
if(k&)num=num*x%mod;
x=x*x%mod;
k>>=;
}
return num;
}
void work(){
inv[]=rec[]=rec[]=;
for(int i=;i<=mod-;i++)rec[i]=rec[i-]*i%mod;
inv[mod-]=ksm(rec[mod-],mod-);
for(int i=mod-;i>=;i--)inv[i]=inv[i+]*(i+)%mod;
}
ll cal(ll x,ll y){
if(x<y)return ;
if(!y||!x)return ;
return rec[x]*inv[y]%mod*inv[x-y]%mod;
}
ll C(ll x,ll y){
if(x<y)return ;
if(!y)return ;
return C(x/mod,y/mod)*cal(x%mod,y%mod)%mod;
}
int main()
{
scanf("%d",&t);
work();
while(t--){
scanf("%lld%lld%lld",&n,&m,&k);
if(k==){
n%=mod,m%=mod;
printf("%lld\n",n*m%mod);
continue;
}
minn=min(n,m);
ans=;
if(n>m)swap(n,m);
ans=(ans+n%mod*C(m,k)%mod+m%mod*C(n,k))%mod;
ans=(ans+*(*C(n,k+)%mod+(m-n+)%mod*C(n,k))%mod)%mod;
if(k==){
minn%=mod;
long long n1=n,m1=m;
n%=mod,m%=mod;
minn=((min(n1,m1)-)/)%mod;
ans=(ans+*(minn*n%mod*m%mod-*(+minn)%mod*minn%mod*inv[]%mod*(m+n)%mod+*minn%mod*(minn+)%mod*(*minn+)%mod*ksm(,mod-)%mod+mod)%mod)%mod;
}
else if(k==){
minn%=mod;
long long n1=n,m1=m;
n%=mod,m%=mod;
ans=(ans+(minn*n%mod*m%mod-(+minn)*minn%mod*inv[]%mod*(m+n)%mod+minn*(minn+)%mod*(*minn+)%mod*ksm(,mod-)%mod+mod)%mod)%mod;
minn=min(m1/,n1)%mod;
ans=(ans+*(minn*n%mod*m%mod-(+minn)*minn%mod*inv[]%mod*(m+*n)%mod+*minn%mod*(minn+)%mod*(*minn+)%mod*ksm(,mod-)%mod+mod)%mod)%mod;
swap(n1,m1);
swap(n,m);
minn=min(m1/,n1)%mod;
ans=(ans+*(minn*n%mod*m%mod-(+minn)*minn%mod*inv[]%mod*(m+*n)%mod+*minn%mod*(minn+)%mod*(*minn+)%mod*ksm(,mod-)%mod+mod)%mod)%mod;
minn=((min(n1,m1)-)/)%mod;
ans=(ans+*(minn*n%mod*m%mod-*(+minn)%mod*minn%mod*inv[]%mod*(m+n)%mod+*minn%mod*(minn+)%mod*(*minn+)%mod*ksm(,mod-)%mod+mod)%mod)%mod;
}
else if(k==){
minn%=mod;
long long n1=n,m1=m;
n%=mod,m%=mod;
ans=(ans+*(minn*n%mod*m%mod-(+minn)*minn%mod*inv[]%mod*(m+n)%mod+minn*(minn+)%mod*(*minn+)%mod*ksm(,mod-)%mod+mod)%mod)%mod;
minn=min(m1/,n1)%mod;
ans=(ans+*(minn*n%mod*m%mod-(+minn)*minn%mod*inv[]%mod*(m+*n)%mod+*minn%mod*(minn+)%mod*(*minn+)%mod*ksm(,mod-)%mod+mod)%mod)%mod;
swap(n1,m1);
swap(n,m);
minn=min(m1/,n1)%mod;
ans=(ans+*(minn*n%mod*m%mod-(+minn)*minn%mod*inv[]%mod*(m+*n)%mod+*minn%mod*(minn+)%mod*(*minn+)%mod*ksm(,mod-)%mod+mod)%mod)%mod;
}
printf("%lld\n",ans);
}
return ;
}
/*
3
7 7 3
7 6 3
8 9 3 1
5 5 1
*/
记一下平方和公式:
差点忘了这个:
朱世杰恒等式
其实它和平方和公式也有点联系
2019.10.22 csp-s模拟测试82 反思总结的更多相关文章
- 2019.8.3 [HZOI]NOIP模拟测试12 C. 分组
2019.8.3 [HZOI]NOIP模拟测试12 C. 分组 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 刚看这题觉得很难,于是数据点分治 k只有1和2两种,分别 ...
- 2019.8.3 [HZOI]NOIP模拟测试12 B. 数颜色
2019.8.3 [HZOI]NOIP模拟测试12 B. 数颜色 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 数据结构学傻的做法: 对每种颜色开动态开点线段树直接维 ...
- 2019.8.3 [HZOI]NOIP模拟测试12 A. 斐波那契(fibonacci)
2019.8.3 [HZOI]NOIP模拟测试12 A. 斐波那契(fibonacci) 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 找规律 找两个节点的lca,需 ...
- 2019.8.14 NOIP模拟测试21 反思总结
模拟测试20的还没改完先咕着 各种细节问题=错失190pts T1大约三分钟搞出了式子,迅速码完,T2写了一半的时候怕最后被卡评测滚去交了,然后右端点没有初始化为n…但是这样还有80pts,而我后来还 ...
- 2019.8.9 NOIP模拟测试15 反思总结
日常爆炸,考得一次比一次差XD 可能还是被身体拖慢了学习的进度吧,虽然按理来说没有影响.大家听的我也听过,大家学的我也没有缺勤多少次. 那么果然还是能力问题吗……? 虽然不愿意承认,但显然就是这样.对 ...
- 2019.8.1 NOIP模拟测试11 反思总结
延迟了一天来补一个反思总结 急匆匆赶回来考试,我们这边大家的状态都稍微有一点差,不过最后的成绩总体来看好像还不错XD 其实这次拿分的大都是暴力[?],除了某些专注于某道题的人以及远程爆踩我们的某学车神 ...
- 2019/10/17 CSP模拟 总结
T1 补票 Ticket 没什么好说的,不讲了 T2 删数字 Number 很后悔的是其实考场上不仅想出了正解的方程,甚至连优化都想到了,却因为码力不足只打了\(O(n^2)\)暴力,甚至还因为细节挂 ...
- 2019.10.30 csp-s模拟测试94 反思总结
头一次做图巨的模拟题OWO 自从上一次听图巨讲课然后骗了小礼物以后一直对图巨印象挺好的233 T1: 对于XY取对数=Y*log(x) 对于Y!取对数=log(1*2*3*...*Y)=log1+lo ...
- 2019.10.25 csp-s模拟测试86 反思总结
继续存档 早上来补了一下昨天的题,不过肯定这两天的没法完全补起来 T1: 经典思路:关于位运算的题讨论每一位的贡献 #include<iostream> #include<cstdi ...
随机推荐
- DRF 序列化组件单增
目录 自定义序列化(矬) Serializer类(方式繁琐) 底层序列化类 UserSerializer 视图序列化步骤 底层反序列化类 UserCreatSerializer 视图反序列化步骤 Mo ...
- 3、变量+运算符+Scanner
1.变量 1>开辟内存空间 int num ; 2>赋值 num = 10; 3>使用 num 1*long 类型的特殊 long num = 12L 2*float类型特殊 flo ...
- php计算网段内所有IP,分配子网段
由于最近业务需要,写了个获取网段内所有IP的函数,以及分配可用子网段的函数 /** * 根据网段获取计算所有IP * @param string $segment 网段 '139.217.0.1/24 ...
- codeforces 1136E-Nastya Hasn't Written a Legend
传送门:QAQQAQ 题意:有一个数组a和一个数组k,数组a一直保持一个性质:a[i + 1] >= a[i] + k[i].有两种操作:1,给某个元素加上x,但是加上之后要保持数组a的性质.比 ...
- JS基础语法之DOM02(事件)
1.常用事件 1.onclick 单击 应用场景:为按钮绑定 2.ondbclick 双击 3.onfocus 获得焦点 4.onblur 失去焦点 应用场景:用于表单验证,用户离开某个输入框时, ...
- <每日一题>题目15:mysql创建表及相关约束
题目: 解答: 第一个表创建: create table class( cid int not null auto_increment primary key, caption char(20) no ...
- PKU--1976 A Mini Locomotive (01背包)
题目http://poj.org/problem?id=1976 分析:给n个数,求连续3段和的最大值. 这个题目的思考方式很像背包问题. dp[i][j]表示前i个数字,放在j段的最大值. 如果选了 ...
- elasticsearch java 索引操作
1.添加maven依赖 <dependency> <groupId>org.elasticsearch</groupId> <artifactId>el ...
- 关于slf4j和log4j冲突问题(自己项目配置文件不生效)
用-Dlog4j.debug可以打印出配置log4j的配置文件加载的信息 mvn dependency:tree 看依赖信息 然后排除掉重复得依赖 <dependencies> <d ...
- hdu1693 Eat the Trees [插头DP经典例题]
想当初,我听见大佬们谈起插头DP时,觉得插头DP是个神仙的东西. 某大佬:"考场见到插头DP,直接弃疗." 现在,我终于懂了他们为什么这么说了. 因为-- 插头DP很毒瘤! 为什么 ...