mcfx's blog - 2017年1月
/2017/01/
个人博客,(曾经)基本只放题解,现在随便写点啥了吧(
-
对于各种并查集写法速度的研究
/archives/176/
2017-01-24T19:59:00+08:00
2018.3.3:更新了测试代码,加入了更多写法,修复了一些致命错误
测试机CPU为Intel® Celeron® Processor G3900,内存为8GB DDR4,系统为Debian 9。
编译命令为g++ test.cpp -o test -O3。
先放测试代码:
```c++
#include
#include
#include
#include
#define N 1024
#define T 100000
int fa[N+233],st[N+233],sz[N+233];
int find1(int x)
{
return x==fa[x]?x:fa[x]=find1(fa[x]);
}
inline int find2(int x)
{
return x==fa[x]?x:fa[x]=find2(fa[x]);
}
inline int find3(int x)
{
while(x!=fa[x])x=fa[x]=fa[fa[x]];return x;
}
inline int find4(int x)
{
int se=0;st[0]=x;
while(fa[x]!=x)st[++se]=x=fa[x];
while(se)fa[st[--se]]=x;
return x;
}
inline int find5(int x)
{
int t=x,p;
while(x!=fa[x])x=fa[x];
while(t!=x)p=fa[t],fa[t]=x,t=p;
return x;
}
int find6(int x)
{
return 0>fa[x]?x:fa[x]=find6(fa[x]);
}
inline int find7(int x)
{
return 0>fa[x]?x:fa[x]=find7(fa[x]);
}
inline int find8(int x)
{
while(fa[x]>=0&&fa[fa[x]]>=0)x=fa[x]=fa[fa[x]];return fa[x]
-
BZOJ 3160: 万径人踪灭
/archives/175/
2017-01-20T22:21:00+08:00
###Description
略。见[BZOJ3160][1]
###Solution
对于“不能是连续的一段”,可以先计算所有答案,然后减去连续一段的,即回文串,这个用回文自动机或者manacher可以得出
考虑以每个位置为中心的对称元素对个数f[i],那么i位置对答案的贡献是$$2^{f[i]}-1$$
如果把a视为1,b视为-1,然后把原串长度\*4,卷积,那么以i为中心的元素对如果相同,则贡献1,否则贡献-1
###Code
```c++
#include
typedef double lf;
#define fo0(i,n) for(int i=0,i##end=n;i>1|(i&1)nxt[u];
}
cur=tmp;
}
}
}
inline void count()
{
for(node *x=tm-1;x>=t;x--)
if(x->fail)x->fail->cnt+=x->cnt;
}
#define P 1000000007
inline int cnt()
{
int ans=0;
for(node *x=tm-1;x>t+1;x--)
ans=mod(ans+x->cnt,P);
return ans;
}
char s[100000];
num p[N];
int po[100001];
int main()
{
scanf("%s",s);
int n=strlen(s);
fo1(i,n/2+5)po[i]=mod(mod(po[i-1]*2+1,P),P);
int y=0;
while((1
-
BZOJ 2989: 数列 & 4170: 极光
/archives/163/
2017-01-08T00:20:00+08:00
###Description
给定一个长度为n的正整数数列a[i]。
定义2个位置的graze值为两者位置差与数值差的和,即graze(x,y)=|x-y|+|a[x]-a[y]|。
2种操作(k都是正整数):
1.Modify x k:将第x个数的值修改为k。
2.Query x k:询问有几个i满足graze(x,i)
-
BZOJ 4750: 密码安全
/archives/161/
2017-01-01T22:54:00+08:00
###Description
有些人在社交网络中使用过许多的密码,我们通过将各种形式的信息转化为 01 信号,再转化为整数,可以将这个人在一段时间内使用过的密码视为一个长度为 n 的非负整数序列 A_1,A_2,...,A_n 。一个人相邻几次在社交网络中使用的密码很有可能是类似的,这使得密码并不是足够安全。为了检验某些人在某些时间段内是否可能受到不安全的影响,我们需要计算上述序列的复杂程度。
![aa.jpg][1]
的值,这将作为我们评估密码复杂程度的一个部分。由于答案可能很大,你只需要给出答案对10^9+61 取模的值即可。
###Input
第一行包含一个正整数 T ,表示有 T 组测试数据。
接下来依次给出每组测试数据。对于每组测试数据:
第一行包含一个正整数 n 。
第二行包含 n 个非负整数,表示 A_1,A_2,?,A_n 。
保证在一行中的每个整数之间有恰好一个空格,没有其他额外的空格。
100% 的数据满足:1≤T≤200,1≤n≤10^5,1≤∑n≤10^6,0≤A_i≤10^9
###Output
对于每组数据输出一行,包含一个整数,表示答案对10^9+61 取模的值。
###Sample Input
3
1
61
5
1 2 3 4 5
5
10187 17517 24636 19706 18756
###Sample Output
3721
148
821283048
###Solution
单调栈扫一遍得到以每个数为最大值的区间,然后按位记前缀xor和的前缀和,对每个数分别统计答案
###Code
```c++
#include
#define P 1000000061
int s[100001],S[100001],l[100001],r[100001],G[100010],*C=G+9;
int main()
{
int T;for(scanf("%d",&T);T--;)
{
int n,m=0,i,j,t,p,A=0;
scanf("%d",&n);s[n]=2e9;
for(i=0;i