zoukankan      html  css  js  c++  java
  • X000101

    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('
    ')) {
    		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 imes 10^6)
    但是按这个上界开数组肯定空间爆炸
    因为单词前缀重合较多、数据良心等原因,实际上节点个数远远达不到这个级别
    所以开到 (5 imes 10^5) 就够了 同时也不会MLE


    P6392 中意

    (ans=leftlceil dfrac{b imes 2^{a+2}}{25} ight ceil imes 100) 的值

    (25 | b imes 2^{a+2}) ,即 (25 | b) 时,上取整可以直接去掉,(ans=4b imes 2^{a+2})
    (25 mid b) ,则上取整相当于下取整再加 1 , (ans=leftlfloor dfrac{b imes 2^{a+2}}{25} ight floor imes100+100)
    (leftlfloor dfrac{b imes 2^{a+2}}{25} ight floor=dfrac{b imes 2^{a+2}-(b imes 2^{a+2}mod 25)}{25})
    代入得 (ans=4[b imes 2^{a+2}-(b imes 2^{a+2}mod 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
    ",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) 时,要考虑所有满足 (yle r_i) 的配对
    所以我们在完成了询问 (1sim i-1) 的基础上,只需要再加入 (r_{i-1}<yle r_i) 的配对即可
    左边界要求 (xge l_i)
    用树状数组存储已加入的配对中靠左元素的位置 (x)
    那么这就是个裸的区间查询了

    最后要按照题目要求计算答案
    时间复杂度为 (O(nlog 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
    ",ans); //要开long long
    	return 0;
    }
    

    P2233 [HNOI2002]公交车路线

    显然可以递推

    (f_{i,j}) 表示换了 (i) 次车最终到达 (j) 站的方案数( (j=0sim7) 依次对应 (Asim H)
    则有 (egin{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 年的省选题,在当时的评测机配置下显然会超时

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

    (egin{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}= egin{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&0end{bmatrix} egin{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^3log 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
    ",f.c[4][0]);
    	return 0;
    }
    

    P4317 花神的数论题

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

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

    (f_{i,j}) 表示最高 (i) 位中有 (j)(1) ,且小于 (n) 的数的个数
    (总位数与 (n) 的二进制表示位数保持一致,不够补前导零)
    (因为 (nle 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
    ",ans);
    	return 0;
    }
    

    AT5140 [AGC035C] Skolem XOR Tree

    很好的构造题

    考察到异或的性质:对于偶数 (x)(xoplus x+1=1)
    按下图所示方法构造,即可使 (2i)(n+2i)(2i+1)(n+2i+1) 的路径均满足题意

    (n+1) 的构造无法这样给出
    样例中 (n=3) 的情况提示我们 (1oplus 2oplus 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,yle n)(x e 3,y e 3)
    还要满足 (noplus xoplus 1oplus yoplus n=n) ,即 (xoplus y=noplus 1)
    随便找一组合法的 (x,y) 即可
    我选的是 (x=operatorname{lowbit}(n),y=noplus 1oplus x)

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

    #include<stdio.h>
    inline void edge(int x,int y) { printf("%d %d
    ",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;
    }
    
  • 相关阅读:
    Arduino学习笔记10
    Arduino学习笔记07
    Arduino学习笔记6
    Arduino学习笔记5
    Arduino学习笔记4
    Arduino学习笔记3
    linux下库文件的编程
    学习编程语言究竟学什么
    Arduino学习笔记2---数字温度计
    Arduino学习笔记0---开发板的了解
  • 原文地址:https://www.cnblogs.com/REKonib/p/14942225.html
Copyright © 2011-2022 走看看