P3879 [TJOI2010]阅读理解

考虑用 Trie 解决

#include<stdio.h>
#include<bitset>
#include<string.h>
#define rep(i,n) for (int i=0; i<n; ++i)
int n,m,t=1,cnt=1,l,*p,a[500000][26];
char c[20]; std::bitset<1010>v[500000];
int main() {
scanf("%d",&n);
rep(i,n) for (scanf("%d",&m); m; --m) {
scanf("%s",c),l=strlen(c),p=&t;
rep(j,l) p=&a[*p][c[j]-97],*p||(*p=(++cnt));
v[*p][i]=1;
}
for (scanf("%d",&m); m; --m,putchar('\n')) {
scanf("%s",c),l=strlen(c),p=&t;
for (int i=0; i<l&&*p; ++i) p=&a[*p][c[i]-97];
rep(i,n) v[*p][i]&&(printf("%d ",i+1),0);
}
return 0;
}

其实是很裸的模板题了 主要问题在于空间占用

首先可以用 bitset 代替 bool 数组来省空间

然后要考虑 Trie 包含的节点个数

容易看出节点个数不超过所有文章的总字母数,也就是 \(5\times 10^6\)

但是按这个上界开数组肯定空间爆炸

因为单词前缀重合较多、数据良心等原因,实际上节点个数远远达不到这个级别

所以开到 \(5\times 10^5\) 就够了 同时也不会MLE


P6392 中意

求 \(ans=\left\lceil \dfrac{b\times 2^{a+2}}{25} \right\rceil \times 100\) 的值

当 \(25 | b\times 2^{a+2}\) ,即 \(25 | b\) 时,上取整可以直接去掉,\(ans=4b\times 2^{a+2}\)

若 \(25 \nmid b\) ,则上取整相当于下取整再加 1 , \(ans=\left\lfloor \dfrac{b\times 2^{a+2}}{25}\right\rfloor\times100+100\)

而 \(\left\lfloor \dfrac{b\times 2^{a+2}}{25}\right\rfloor=\dfrac{b\times 2^{a+2}-(b\times 2^{a+2}\bmod 25)}{25}\)

代入得 \(ans=4[b\times 2^{a+2}-(b\times 2^{a+2}\bmod 25)]+100\)

务必注意对 \(25\) 取模之前不要对 \(998344353\) 取模

\(b\) 非常大,所以读入时就要取模,模 \(25\) 和模 \(998344353\) 也要分开算

#include<stdio.h>
#include<ctype.h>
const int P=998344353,p=25;
int s1,s2,x1=2,x2=2; long long a; char ch; int main() {
for (ch=getchar(); isdigit(ch); ch=getchar())
s1=(10ll*s1+(ch^48))%P,s2=(s2*10+(ch^48))%p;
for (scanf("%lld",&a),a+=2; a; a>>=1)
(a&1)&&(s1=1ll*s1*x1%P,s2=s2*x2%p),
x1=1ll*x1*x1%P,x2=x2*x2%p;
s1=4ll*(s1-s2+P)%P,s2&&(s1=(s1+100)%P);
printf("%d\n",s1);
return 0;
}

P5677 [GZOI2017]配对统计

首先研究一下“好的配对”

其实就是先确定 \(a_x\) ,要找到 \(a_y\) 使两者差的绝对值最小

对 \(a\) 排序,那么符合条件的 \(a_y\) 排序后肯定与 \(a_x\) 相邻

很容易就能找出所有“好的配对” \((x,y)\)

注意 \((x,y)\) 和 \((y,x)\) 其实是有区别的,但是在查询的时候两者等价,所以不妨令 \(x<y\)

然后来处理查询

同时考虑左右边界不方便,所以我们通过排序先处理掉一边

将所有查询离线,按右边界 \(r\) 的大小升序排序

再将所有“好的配对”按靠右元素的位置 \(y\) 升序排序

处理询问 \(i\) 时,要考虑所有满足 \(y\le r_i\) 的配对

所以我们在完成了询问 \(1\sim i-1\) 的基础上,只需要再加入 \(r_{i-1}<y\le r_i\) 的配对即可

左边界要求 \(x\ge l_i\)

用树状数组存储已加入的配对中靠左元素的位置 \(x\)

那么这就是个裸的区间查询了

最后要按照题目要求计算答案

时间复杂度为 \(O(n\log n)\) (认为 \(n,m\) 同级)

#include<stdio.h>
#include<ctype.h>
#include<algorithm>
#define gc (l==r&&(r=(l=c)+fread(c,1,1<<21,stdin),l==r)?EOF:*l++)
const int N=300010,inf=2e9; long long ans;
int n,m,cnt,t,f[N];
inline int lb(int x) { return (-x&x); }
inline void upd(int i) {
for ( ; i<=n; i+=lb(i)) ++f[i];
}
inline int qry(int i) {
int s=0;
for ( ; i; i-=lb(i)) s+=f[i];
return s;
} char c[1<<21],*l=c,*r=c;
inline int read() {
int x=0; char ch=gc;
while (!isdigit(ch)) ch=gc;
while (isdigit(ch)) x=x*10+(ch^48),ch=gc;
return x;
} struct node { int i,x; }a[N];
struct match { int l,r; }b[N];
struct query { int i,l,r; }q[N];
int operator < (node p,node q) { return p.x<q.x; }
int operator < (match p,match q) { return p.r<q.r; }
int operator < (query p,query q) { return p.r<q.r; }
inline void add(int x,int y) {
x>y&&(t=x,x=y,y=t);
b[++cnt]={x,y};
}
int main() {
n=read(),m=read();
for (int i=1; i<=n; ++i) a[i]={i,read()};
std::sort(a+1,a+n+1),a[0].x=-inf,a[n+1].x=inf;
for (int i=1; i<=n; ++i) //找出所有“好的配对”
a[i].x-a[i-1].x<=a[i+1].x-a[i].x&&(add(a[i].i,a[i-1].i),0),
a[i].x-a[i-1].x>=a[i+1].x-a[i].x&&(add(a[i].i,a[i+1].i),0);
for (int i=1; i<=m; ++i) t=read(),q[i]={i,t,read()};
std::sort(b+1,b+cnt+1),std::sort(q+1,q+m+1);
for (int i=1,j=1; i<=m; ++i) {
while (b[j].r<=q[i].r&&j<=cnt) upd(b[j].l),++j; //加入配对
ans+=1ll*q[i].i*(j-1-qry(q[i].l-1)); //j-1为已加入的配对数
}
printf("%lld\n",ans); //要开long long
return 0;
}

P2233 [HNOI2002]公交车路线

显然可以递推

用 \(f_{i,j}\) 表示换了 \(i\) 次车最终到达 \(j\) 站的方案数( \(j=0\sim7\) 依次对应 \(A\sim H\) )

则有 \(\begin{cases}
f_{i,0}=f_{i-1,1}+f_{i-1,7}\\
f_{i,1}=f_{i-1,0}+f_{i-1,2}\\
f_{i,2}=f_{i-1,1}+f_{i-1,3}\\
f_{i,3}=f_{i-1,2}\\
f_{i,4}=f_{i-1,3}+f_{i-1,5}\\
f_{i,5}=f_{i-1,6}\\
f_{i,6}=f_{i-1,5}+f_{i-1,7}\\
f_{i,7}=f_{i-1,0}+f_{i-1,6}
\end{cases}\)

注意到达 \(E\) 站之后就不会再换车了,所以 \(f_{i,3},f_{i,5}\) 与 \(f_{i-1,4}\) 无关

直接递推时间复杂度是 \(O(n)\) 的,可以通过

但这是 2002 年的省选题,在当时的评测机配置下显然会超时

实际上我们可以把递推式写成矩阵乘法的形式

\(\begin{bmatrix}f_{i,0}\\f_{i,1}\\f_{i,2}\\f_{i,3}\\f_{i,4}\\f_{i,5}\\f_{i,6}\\f_{i,7}\end{bmatrix}=
\begin{bmatrix}
0&1&0&0&0&0&0&1\\
1&0&1&0&0&0&0&0\\
0&1&0&1&0&0&0&0\\
0&0&1&0&0&0&0&0\\
0&0&0&1&0&1&0&0\\
0&0&0&0&0&0&1&0\\
0&0&0&0&0&1&0&1\\
1&0&0&0&0&0&1&0\end{bmatrix}
\begin{bmatrix}f_{i-1,0}\\f_{i-1,1}\\f_{i-1,2}\\f_{i-1,3}\\f_{i-1,4}\\f_{i-1,5}\\f_{i-1,6}\\f_{i-1,7}\end{bmatrix}\)

然后写个矩阵加速就可以 \(O(8^3\log n)\) 解决了

#include<stdio.h>
#include<string.h>
#define rep(i) for (int i=0; i<8; ++i)
struct matrix { int c[8][8]; }a,f,t;
matrix operator * (matrix x,matrix y) {
memset(t.c,0,sizeof t.c);
rep(i) rep(j) {
rep(k) t.c[i][j]+=x.c[i][k]*y.c[k][j];
t.c[i][j]%=1000;
}
return t;
} int main() {
f=a={ { {0,1,0,0,0,0,0,1},
{1,0,1,0,0,0,0,0},
{0,1,0,1,0,0,0,0},
{0,0,1,0,0,0,0,0},
{0,0,0,1,0,1,0,0},
{0,0,0,0,0,0,1,0},
{0,0,0,0,0,1,0,1},
{1,0,0,0,0,0,1,0} } };
int n; scanf("%d",&n),--n;
while (n) (n&1)&&(f=f*a,0),a=a*a,n>>=1;
printf("%d\n",f.c[4][0]);
return 0;
}

P4317 花神的数论题

终于看懂了兔队做法 实在太强了%%%

\(\operatorname{sum}(i)\) 的取值范围很小,可以考虑统计每个取值的出现次数

用 \(f_{i,j}\) 表示最高 \(i\) 位中有 \(j\) 个 \(1\) ,且小于 \(n\) 的数的个数

(总位数与 \(n\) 的二进制表示位数保持一致,不够补前导零)

(因为 \(n\le 10^{15}<2^{50}\) ,所以实现的时候统一补到 \(50\) 位)

(不比较第 \(i\) 位之后的数,也就是严格地说,应为最高 \(i\) 位构成的数小于 \(n\) 最高 \(i\) 位构成的数

若前 \(i-1\) 位构成的数已经小于 \(n\) 前 \(i\) 位构成的数,则第 \(i\) 位为 \(1,0\) 均合法

对应的转移方程为 \(f_{i,j}=f_{i-1,j-1}+f_{i-1,j}\)

还需要注意一个特殊情况:若 \(n\) 的第 \(i\) 位为 \(1\) ,那么令前 \(i-1\) 位数字与 \(n\) 的完全相同,第 \(i\) 位数字取 \(0\) ,得到的数也是小于 \(n\) 的

此时 \(1\) 的个数即为 \(n\) 前 \(i-1\) 为中 \(1\) 的个数(设为 \(t\) )

因此,若 \(n\) 的第 \(i\) 位为 \(1\) ,则 \(f_{i,t}\) 应再加 \(1\)

然后 dp 部分就结束了,最后用快速幂计算答案

注意 dp 过程中最好不要取模, \(f_{i,j}\) 最后是在指数上的,而且 \(10000007\) 不是质数,取模必须使用扩展欧拉定理,会比较麻烦

#include<stdio.h>
const int P=10000007;
int t,ans=1; long long n,f[50];
inline int power(int x,long long y) {
int s=1;
while (y) (y&1)&&(s=1ll*s*x%P),x=1ll*x*x%P,y>>=1;
return s;
} int main() {
scanf("%lld",&n);
for (int i=49; ~i; --i) {
for (int j=49; j; --j) f[j]+=f[j-1];
((n>>i)&1)&&(++f[t],++t);
}
++f[t];
for (int i=1; i<=49; ++i)
ans=1ll*ans*power(i,f[i])%P;
printf("%d\n",ans);
return 0;
}

AT5140 [AGC035C] Skolem XOR Tree

很好的构造题

考察到异或的性质:对于偶数 \(x\) , \(x\oplus x+1=1\)

按下图所示方法构造,即可使 \(2i\) 到 \(n+2i\) 、 \(2i+1\) 到 \(n+2i+1\) 的路径均满足题意

但 \(n+1\) 的构造无法这样给出

样例中 \(n=3\) 的情况提示我们 \(1\oplus 2\oplus 3=0\) ,因此直接将 \(1,2,3,n+1,n+2,n+3\) 顺次相连即可

(这改变了 \(2,3,n+2,n+3\) 之间连边的构造方法,但其它节点的依然不变)

最后,如果 \(n\) 为偶数,我们还要考虑 \(n\) 和 \(2n\) 如何构造

最简单的方法是构造路径 \(n-x-1-y-2n\)

\(x,y\) 应与 \(1\) 直接相连,即 \(1<x,y\le n\) 且 \(x\ne 3,y\ne 3\)

还要满足 \(n\oplus x\oplus 1\oplus y\oplus n=n\) ,即 \(x\oplus y=n\oplus 1\)

随便找一组合法的 \(x,y\) 即可

我选的是 \(x=\operatorname{lowbit}(n),y=n\oplus 1\oplus x\)

无解条件:\(n\) 为 \(2\) 的整数次幂,此时无法给出 \(n\) 和 \(2n\) 的构造

#include<stdio.h>
inline void edge(int x,int y) { printf("%d %d\n",x,y); }
int main() {
int n,t; scanf("%d",&n),t=(-n&n); // t=lowbit(n)
if (t==n) return puts("No"),0; //无解
puts("Yes"),edge(1,2),edge(2,3),
edge(3,n+1),edge(n+1,n+2),edge(n+2,n+3);
for (int i=4; i<n; i+=2)
edge(1,i),edge(i,n+i+1),
edge(1,i+1),edge(i+1,n+i);
if ((n&1)==0) edge(t,n),edge(n^t^1,n+n);
return 0;
}

X000101的更多相关文章

随机推荐

  1. Codeforces 567B:Berland National Library(模拟)

    time limit per test : 1 second memory limit per test : 256 megabytes input : standard input output : ...

  2. BeanUtils属性转换工具

    commons 包的 BeanUtils 进行属性拷贝性能较差:Spring 的 BeanUtils 性能相对较好. public class A { private String name; pri ...

  3. Springcloud-alibaba学习实践(2)- nacos&Eureka Server服务注册实践

    前言:上一篇已搭建好了springcloud服务注册中心(Nacos&Eureka Server),本篇继续代码实践,注册服务到服务中心,本篇只是演示了两种注册中心,后续我们以Nacos注册中 ...

  4. [C/C++]linux下c-c++语法知识点归纳和总结

    1.c/c++申请动态内存 在c++中,申请动态内存是使用new和delete,这两个关键字实际上是运算符,并不是函数. 而在c中,申请动态内存则是使用malloc和free,这两个函数是c的标准库函 ...

  5. What's new in Dubbo-go v1.5.1

    近期我们发布了 dubbo-go v1.5.1,虽然是 v1.5 的一个子版本,但相比于 v1.5.0, 社区还是投入了很大人力添加了如下重大改进. 1 应用维度注册模型 在新模型 release 后 ...

  6. 4 - 基于ELK的ElasticSearch 7.8.x技术整理 - 高级篇( 续 ) - 更新完毕

    0.前言 这里面一些理论和前面的知识点挂钩的,所以:建议看一下另外3篇知识内容 基础篇:https://www.cnblogs.com/xiegongzi/p/15684307.html java操作 ...

  7. CGO快速入门

    1. 通过`improt "C"`语句开启CGO特性2. `/**/`中间是C代码,之后接 import "C" 如果存在空行 就会报错.could not d ...

  8. VMware_克隆机器后主机Ping不同虚拟机,虚拟机能Ping通主机

    使用vm的克隆功能克隆一个系统,因为我克隆的系统使用的是静态IP,所以修改克隆机的ip地址,并且也修改MAC地址,启动后两个虚拟机,ping了下主机IP能Ping通,但是使用主机Ping虚拟机时发现P ...

  9. Go语言中各种数据格式转换

    Go语言各种数据类型格式转换 package main import ( "encoding/json" "fmt" "reflect" & ...

  10. vue-json-editor可视化编辑器的介绍与应用

    vue-json-editor可视化编辑器 最近项目中有用到json编辑器,我选用了这款vue的编辑器,看起来也是比较简洁,接下来就具体介绍一下它,以及内部属性. 一.vue-json-editor的 ...