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 ...
随机推荐
- Python-进程(2)
目录 进程互斥锁 队列 堆栈 IPC(进程间通信) 生产者与消费者模型 进程互斥锁 通过之前的学习,我们千方百计的实现了程序的异步,让多个任务可以同时在几个进程中并发处理 他们之间的运行没有顺序,一旦 ...
- vs Code打开新的文件会覆盖窗口中的文件?
这是因为你单击文件名的缘故,这个是“预览模式”,所以再单击其他文件时,会覆盖当前打开的文件. 如果你要每次都打开新tab,那就双击文件名好了.这个逻辑和sublime是一样的. 补充: 预览模式是现在 ...
- BZOJ 2281 消失之物
ftiasch 有 N 个物品, 体积分别是 W1, W2, -, WN. 由于她的疏忽, 第 i 个物品丢失了. "要使用剩下的 N – 1 物品装满容积为 x 的背包,有几种方法呢?&q ...
- nc 文件的nan识别
表现形式:print()结果为 -- 打印type为numpy.ma.core.MaskedConstant 使用 if type(x) == np.ma.core.MaskedConsta ...
- python 编程 一次错误记录 -1073740791
原因是发生在我错把类当做实例化对象使用了
- 6月份Github上最热门的Java开源项目!
1.halo 这是一个轻快,简洁,功能强大,使用Java开发的博客系统. 项目地址:https://github.com/halo-dev/halo Star 6139 2.jeecg-boot ...
- JavaScript事件(随笔)
1. Javascript事件介绍 JavaScript中的事件和现实生活中的事件类似,现实生活中发生的一些事情,例如:交通事件,当这些事情发生时,我们需要提供处理方案: 在JavaScript中事件 ...
- BMP 图片格式
BMP根据颜色深度,可以分为2(1位).16(4位).256(8位).65536(16位)和1670万(24位)以及32位含有alpha通道.8位图像可以是 索引彩色图像外,也可以是灰阶图像,而索引 ...
- vue.js_12_vue的watch和computed
1.watch用来监测指定Vue实例上的数据变动. watch主要用于监控vue实例的变化,它监控的变量当然必须在data里面声明才可以,它可以监控一个变量,也可以是一个对象. 1.>使用wat ...
- linux 编译C语言代码后产生OBJ文件的方法
如果你不指定编译成什么文件,gcc默认一步到位,直接生成可执行文件你可以试试以下几个参数 -c 只激活预处理,编译,和汇编,也就是他只把程序做成obj文件 例子用法: gcc -c hello.c 他 ...