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. 全网连夜修复的Log4j漏洞,如何做到一行代码都不改?

    GitHub 21.5k Star 的Java工程师成神之路,不来了解一下吗! GitHub 21.5k Star 的Java工程师成神之路,真的不来了解一下吗! Apache Log4j2 远程代码 ...

  2. MySQL中写操作

    具体到操作流程: 当执行某个写操作的 SQL 时,引擎将这行数据更新到内存的同时把对应的操作记录到 redo log 里面,然后处于 prepare 状态.并把完成信息告知给执行器. 执行器生成对应操 ...

  3. 「HAOI2016」找相同字符

    知识点: SA,线段树,广义 SAM 原题面 Loj Luogu 给定两字符串 \(S_1, S_2\),求出在两字符串中各取一个子串,使得这两个子串相同的方案数. 两方案不同当且仅当这两个子串中有一 ...

  4. Chapter 9 Measurement Bias

    目录 9.1 Measurement Error The structure of measurement error 9.3 Mismeasured confounders 9.4 Intentio ...

  5. 跨域The 'Access-Control-Allow-Origin' header contains multiple values '*, *', but only one is allowed.解决方案

    使用Ajax跨域请求资源,Nginx作为代理,出现:The 'Access-Control-Allow-Origin' header contains multiple values '*, *', ...

  6. Java Web程序设计笔记 • 【第7章 会话跟踪技术】

    全部章节   >>>> 本章目录 7.1 会话跟踪技术概述 7.1.1 为什么需要会话跟踪 7.1.2 会话的状态和跟踪 7.1.3 会话跟踪技术 7.1.4 会话跟踪工作流程 ...

  7. playwright--自动化(一):快速上手

    Playwright为现代 Web 应用程序提供可靠的端到端测试. 在JavaScript 和 TypeScript.Python..NET和Java 中都可以使用 Playwright 本人选择py ...

  8. 【计理05组01号】R 语言基础入门

    R 语言基本数据结构 首先让我们先进入 R 环境下: sudo R 赋值 R 中可以用 = 或者 <- 来进行赋值 ,<- 的快捷键是 alt + - . > a <- c(2 ...

  9. Swoole 中使用通道(Channel)实现协程间通讯(消息队列)

    通道 Coroutine\Channel 使用本地内存,不同的进程之间内存是隔离的. 只能在同一进程的不同协程内进行 push 和 pop 操作. Co::set(['hook_flags'=> ...

  10. python的作用域、globals()-全局变量 和 locals()-局部变量

    在python中,函数会创建一个自己的作用域,也称为为命名空间.当我们在函数内部访问某个变量时,函数会优先在自己的命名空间中寻找. 我们自己定义的全局变量均在python内建的globals()函数中 ...