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 ...
随机推荐
- js页面的弹框怎么关闭啊
1.单纯的关闭window.opener.location.reload(); //刷新父窗口中的网页window.close();//关闭当前窗窗口2.提交后关闭 function save(){d ...
- php中的线程、进程和并发区别
https://mp.weixin.qq.com/s/Ps5w13TTmpnZx-RPWbsl1A 进程 进程是什么?进程是正在执行的程序:进程是正在计算机上执行的程序实例:进程是能分配给处理器并由处 ...
- Windows的进程间通信
对于任何一个现代的操作系统,进程间通信都是其系统结构的一个重要组成部分.而说到Windows的进程(线程)间通信,那就要看是在什么意义上说了.因为正如"Windows的跨进程操作" ...
- Android基础控件SeekBar拖动条的使用
1.简介 SeekBar继承ProgressBar,相关属性和三种不同状态下的触发方法: <!--<SeekBar--> <!--android:layout_width=&q ...
- Linux虚拟机ip为127.0.0.1的处理
Redhat系列(Cnetos)打配置文件在/etc/sysconfig/network-scripsts/ifcfg-eth0(在Centos6.5开始就有这种情况了) 打开配置文件找到ONBOOT ...
- 04-3-object类型
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Java 多线程同步和异步详解
java线程 同步与异步 线程池 1)多线程并发时,多个线程同时请求同一个资源,必然导致此资源的数据不安全,A线程修改了B线 程的处理的数据,而B线程又修改了A线程处理的数理.显然这是由于全局资源造成 ...
- elasticsearch query 和 filter 的区别
Query查询器 与 Filter 过滤器 尽管我们之前已经涉及了查询DSL,然而实际上存在两种DSL:查询DSL(query DSL)和过滤DSL(filter DSL).过滤器(filter)通常 ...
- 关于bind
1, 目的 使程序可以感知到事件 2, 格式 widget.bind(event, handler) 3, handler注意事项 在这里, handler作为一个函数, 是需要一个event对象作为 ...
- jQuery4操作表单+属性+样式
一.动态添加表格 <!DOCTYPE html> <html lang="en"> <head> <meta charset=" ...