zoukankan      html  css  js  c++  java
  • 1006

    hh A题算了下空间感觉没问题 没想到开了4个数组 成功bao 0
    期望290 实际 175
    naiive

    A.劳伦斯数
    数学家劳伦斯定义: 对于任意整数 x, 如果 x 是素数, 或者 x 可以表示成两个素数的乘积, 那
    么 x 就称为劳伦斯数。
    现在给出 Q 个询问, 每个询问形如“L R” , 需要你快速统计出区间[L,R]中有多少个劳伦斯
    数。
    解:
    这题肯定和线性筛有关系
    然后打了一波板子后 发现 对于x 表示成两个素数的乘积的形式 我们可以这样想想
    当i是一个质数 那么i*pri[j] 就会满足条件 并且由于线性筛的特性 pri[j] 一定是一个最小的质因数

    就像这样

    	if(phi[le]==i)
    			{
    				p[i*phi[j]]=1;
    			}
    

    或者定义pr[x] 表示x 的最小质因数
    那么充要条件为 pr[i/pr[i]]=i/pr[i]; 即最小的质因数是自己就满足素数的条件

    考完后我发现自己还是太naiive
    看到可能int 溢出不知道强制类型转换 省掉空间
    看到标记的数组还开long long
    1e9+1 搞定的事情 自己非要数着写

    B.逃离迷宫
    文件名: escape.cpp
    输入输出名: escape.in/escape.out
    时空限制 1s, 256m
    题目描述
    队员们在玩一款迷宫游戏。 在一个山体迷宫中, 共有 N 个山洞, 编号 1 到 N。
    游戏开始时, 队员们位于 1 号山洞, 出口在 N 号山洞。 每个山洞里面可能有一些通行卡, 进入
    一个山洞, 队员们就能获得该山洞的通行卡。 通行卡有 K 种, 编号 1 到 K。 山洞之间存在单向道路,
    每条道路都需要拥有指定编号的通行卡才能通过。
    通过一条道路的时间是 1 分钟, 队员们想知道, 最少多少分钟, 就能走到出口。
    输入格式:
    第一行, 三个整数 N,M,K, 表示山洞数、 道路数和通行卡种数
    接下来 K 行, 其中第 i 行描述 i 号山洞存在的通行卡的情况, 用 N 个空格间隔的 0 或 1 来表
    示。 若其中第 j 个数为 1, 表示该山洞存在 j 号通行卡, 为 0 则表示不存在第 j 号通行卡。
    接下来 M 行, 每行描述一条道路的情况。 首先是两个数 X 和 Y, 表示有一条从 X 出发到达 Y
    的通道。 接下来 K 空格间隔的个 0 或 1, 表示通过该通道需要拥有的通行卡的情况, 若其中第 j 个
    数为 1, 表示需要 j 号通行卡, 为 0 则表示不需要。
    输出格式:
    一个整数, 表示最少所需时间。 若无法到达出口, 输出“No Solution” 。
    样例输入:
    3 3 2
    1 0
    0 1
    0 0
    1 3 1 1
    1 2 1 0
    2 3 1 1
    样例输出:
    2

    解:
    多维最短路+状压DP
    定义f[i][j] 表示 在i 号点 集合为j 所需要的最小时间
    满足条件: $ ((r.s$ & $ le[i])==le[i])$
    转移为: ( if(dis[r.f][r.s]+1<dis[u][(r.s)|w[u]]) { dis[u][(r.s)|w[u]]=dis[r.f][r.s]+1, if(!mark[u][(r.s)|w[u]]) { mark[u][(r.s)|w[u]]=1; } } )

    代码:

    //
    #include<bits/stdc++.h>
    using namespace std;
    #define maxnn 6010
    int mark[maxnn][1<<11];
    int n,m,k;
    int all=0;
    int las[maxnn],en[maxnn],le[maxnn],tot,nex[maxnn];
    int dis[maxnn][1<<11];
    int w[maxnn];
    typedef pair<int ,int > P;
    #define f first 
    #define s second
    #define inf 100000000
    void add(int a ,int b,int c)
    {
    	en[++tot]=b;
    	nex[tot]=las[a];
    	las[a]=tot;
    	le[tot]=c;
    }
    void spfa()
    {
    	queue<P> Q;
    	for(int i=1;i<=n;i++)
    	{
    		for(int j=0;j<=all;j++){
    			dis[i][j]=inf;
    			mark[i][j]=0;
    		}
    	}
    	dis[1][w[1]]=0;
    	mark[1][w[1]]=1;
    	Q.push(make_pair(1,w[1]));
    	while(Q.size())
    	{
    		P r=Q.front();
    		Q.pop();
    		mark[r.f][r.s]=0;
    		for(int i=las[r.f];i;i=nex[i])
    		{
    			int u=en[i];
    			if(!((r.s&le[i])==le[i]))continue;
    			if(dis[r.f][r.s]+1<dis[u][(r.s)|w[u]])
    			{
    				dis[u][(r.s)|w[u]]=dis[r.f][r.s]+1;
    				if(!mark[u][(r.s)|w[u]])
    				{
    					mark[u][(r.s)|w[u]]=1;
    					Q.push(make_pair(u,(r.s)|w[u]));
    				}
    			}
    		}
    	}
    }
    
    void FIE()
    {
    	freopen("escape.in","r" ,stdin);
    	freopen("escape.out","w",stdout);
    }
    int main()
    {
    	//FIE();
    	int x,y,z;
    	scanf("%d%d%d",&n,&m,&k);
    	all=(1<<k)-1;
    	for(int i=1;i<=n;i++)
    	{
    		for(int j=1;j<=k;j++){
    			scanf("%d",&z);
    			if(z==1)
    			w[i]=w[i]|((1<<j-1));
    		}
    	}
    	for(int i=1;i<=m;i++)
    	{
    		scanf("%d%d",&x,&y);
    		int tmp=0;
    		for(int j=1;j<=k;j++){
    			cin>>z;
    			if(z==1)
    			tmp=tmp|((1<<j-1));
    		}
    		add(x,y,tmp);
    	}
    	spfa();
    	int ans=100000000;
    	for(int i=0;i<=all;i++){
    		ans=min(ans,dis[n][i]);
    	}
    	if(ans==100000000)
    	{
    		puts("No Solution");
    	}
    	else
    	printf("%d",ans);
    }
    

    C 线路重叠
    某城市有非常发达的公共交通系统。 有 N 个公交站, 通过 N-1 条双向道路连接起来。 公交站编
    号 1 到 N, 任意两个公交站都可以相互到达。
    队员们提出 Q 个询问, 每个询问形如“X Z Y” , 表示问从 X 到 Z 的公交线路, 与从 Y 到 Z 的
    公线路, 存在多少个重叠的车站。 重叠指车站既在 X 到 Z 路线中, 也在 Y 到 Z 路线中。
    输入格式:
    第一行, 两个整数 N 和 Q, 表示询问数
    接下来 N-1 行, 每行两个整数 X 和 Y, 表示编号 X 和 Y 的公交站存在道路相连。
    接下来 Q 行, 每行三个整数 X,Z,Y, 表示一次询问
    输出格式:
    Q 行, 每行一个整数, 对应一次询问的答案
    样例输入:
    3 3
    1 2
    2 3
    1 2 3
    1 1 3
    3 1 3
    样例输出:
    1 1 3

    解:
    考场上没有注意到这是一个固定终点的问题 敲了一发树剖 T 75 旁边的某位ruan姓jul 打的比我复杂T90 我... 充分证明了fread 的重要性 时间复杂度(O(Q imes (log2(n))^2))
    考试后 利用树状数组优化 还是T90...
    树剖的想法很好想
    对于一段距离 在这条路径上+1 对于另一段距离 在他的路径上查询区间和 然后删去
    发一波我写的树状数组的树剖

    ((k+1) sum c[i] - sum x*c[i])
    x 与 k 均为 add和get 函数里面 i的初始值

    inline void add(int a ,int b) {
    	en[++tot]=b;
    	nex[tot]=las[a];
    	las[a]=tot;
    }
    inline void ad1(int x,int d)
    {
    	for(int i=x;i<=n+100;i+=lowbit(i))
    	{
    		c1[i]+=d;
    	}
    }
    inline void ad2(int x,int d)
    {
    	for(int i=x;i<=n+100;i+=lowbit(i))
    	{
    		c2[i]=c2[i]+x*d;
    	}
    }
    inline int get1(int x)
    {
    	int ans=0;
    	for(int i=x;i;i-=lowbit(i))
    	{
    		ans=ans+(x+1)*c1[i];
    	}
    	return ans;
    }
    inline int get2(int x)
    {
    	int ans=0;
    	for(int i=x;i;i-=lowbit(i))
    	{
    		ans+=c2[i];
    	}
    	return ans;
    }
    
    //
    
    #include<bits/stdc++.h>
    using namespace std;
    #define maxnn 1000000
    #define maxn 500100
    #define ll long long
    #define lowbit(i) i&(-i) 
    char pbuf[1<<20],*pf=pbuf;
    inline void push(char c)
    {
        if(pf-pbuf==(1<<20))fwrite(pbuf,1,1<<20,stdout),pf=pbuf;
        *pf++=c;
    }
    template<typename T>
    inline void print(T x)
    {
        static short sta[35];
        if(x<0)push('-'),x=-x;
        int TOP=0;
        do{sta[TOP++]=x%10;x/=10;}while(x);
        while(TOP)push('0'+sta[--TOP]);
        push('
    ');
    }
    char buf[1<<20],*p1,*p2;
    #define GC (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?0:*p1++)
    inline int R()
    {
    	char t=GC;
    	int x=0;
    	while(!isdigit(t)) t=GC;
    	while(isdigit(t)) x=x*10+t-48,t=GC;
    	return x;
    }
    int c1[maxnn],c2[maxnn];
    int las[maxn],en[maxn],tot,nex[maxn];
    int n,Q;
    inline void add(int a ,int b) {
    	en[++tot]=b;
    	nex[tot]=las[a];
    	las[a]=tot;
    }
    inline void ad1(int x,int d)
    {
    	for(int i=x;i<=n+100;i+=lowbit(i))
    	{
    		c1[i]+=d;
    	}
    }
    inline void ad2(int x,int d)
    {
    	for(int i=x;i<=n+100;i+=lowbit(i))
    	{
    		c2[i]=c2[i]+x*d;
    	}
    }
    inline int get1(int x)
    {
    	int ans=0;
    	for(int i=x;i;i-=lowbit(i))
    	{
    		ans=ans+(x+1)*c1[i];
    	}
    	return ans;
    }
    inline int get2(int x)
    {
    	int ans=0;
    	for(int i=x;i;i-=lowbit(i))
    	{
    		ans+=c2[i];
    	}
    	return ans;
    }
    int f[maxn][20];
    int dfn[maxnn],cnt;
    inline int go_up(int s,ll k) {
    	int d=log2(n);
    	for(int i=d; i>=0; i--) {
    		if(k&(1<<i)) {
    			s=f[s][i];
    		}
    	}
    	return s;
    }
    ll dep[maxnn];
    int topp[maxnn];
    int son[maxn];
    inline int lca(int x,int y) {
    	if(dep[x]<dep[y])
    		swap(x,y);
    	int s=dep[x]-dep[y];
    	x=go_up(x,s);
    	if(x==y) return y;
    	s=log2(n);
    	for(int i=s; i>=0; i--) {
    		if(f[x][i]!=f[y][i]) {
    			x=f[x][i];
    			y=f[y][i];
    		}
    	}
    	return f[y][0];
    }
    ll size[maxn];
    inline void dfs1(int v,int fa) {
    	int maxson=-1;
    	f[v][0]=fa;
    	dep[v]=dep[fa]+1;
    	int s=log2(n);
    	for(int i=1; i<=s; i++) {
    		f[v][i]=f[f[v][i-1]][i-1];
    	}
    	size[v]=1;
    	for(int i=las[v]; i; i=nex[i]) {
    		int u=en[i];
    		if(u!=fa) {
    			dfs1(u,v);
    			size[v]+=size[u];
    			if(size[u]>maxson)
    			{
    				maxson=size[u];
    				son[v]=u;
    			}
    		}
    	}
    }
    inline void dfs2(int v,int fa,int t) {
    	topp[v]=t;
    	dfn[v]=++cnt;
    	if(son[v]) dfs2(son[v],v,t);
    	for(int i=las[v]; i; i=nex[i]) {
    		int u=en[i];
    		if(u!=fa&&u!=son[v]) {
    			dfs2(u,v,u);
    		}
    	}
    }
    inline void add1(int x,int y,int d)
    {
    	while(topp[x]!=topp[y]){
    		if(dep[topp[x]]<dep[topp[y]])
    		{
    			swap(x,y);
    		}
    		ad1(dfn[topp[x]],d);
    		ad1(dfn[x]+1,-d);
    		ad2(dfn[topp[x]],d);
    		ad2(dfn[x]+1,-d);
    		x=f[topp[x]][0];
    	}
    	if(dep[x]<dep[y])
    		{
    			swap(x,y);
    		}
    	ad1(dfn[y],d);
    	ad1(dfn[x]+1,-d);
    	ad2(dfn[y],d);
    	ad2(dfn[x]+1,-d);
    }
    inline int get(int x,int y)
    {
    	int ans=0;
    	while(topp[x]!=topp[y]){
    		if(dep[topp[x]]<dep[topp[y]])
    		{
    			swap(x,y);
    		}
    		int tmp1=dfn[topp[x]];
    		int tmp2=dfn[x];
    		ans=ans+(get1(tmp2)-get2(tmp2)-(get1(tmp1-1)-get2(tmp1-1)));
    		x=f[topp[x]][0];
    	}
    		if(dep[x]<dep[y])
    		{
    			swap(x,y);
    		}
    		int tmp1=dfn[y];
    		int tmp2=dfn[x];
    		ans=ans+(get1(tmp2)-get2(tmp2)-(get1(tmp1-1)-get2(tmp1-1)));
    		return ans;
    }
    inline void ch1(int x,int y) {
    	if(dep[x]<dep[y]) swap(x,y);
    	int now=lca(x,y);
    	if(now!=y) {
    		add1(now,now,1);
    		int tmp1=dep[x]-dep[now];
    		int id1=go_up(x,tmp1-1);
    		add1(id1,x,1);
    		tmp1=dep[y]-dep[now];
    		int id2=go_up(y,tmp1-1);
    		add1(id2,y,1);
    	} else {
    		add1(y,x,1);
    	}
    }
    inline ll ch2(int x,int y) {
    	ll ans=0;
    	if(dep[x]<dep[y]) swap(x,y);
    	int now=lca(x,y);
    	if(now!=y) {
    		ans+=get(now,now);
    		int tmp1=dep[x]-dep[now];
    		int id1=go_up(x,tmp1-1);
    		ans+=get(id1,x);
    		tmp1=dep[y]-dep[now];
    		int id2=go_up(y,tmp1-1);
    		ans+=get(id2,y);
    	} else {
    		ans+=get(y,x);
    	}
    	return ans;
    }
    inline void era(int x,int y) {
    	if(dep[x]<dep[y]) swap(x,y);
    	int now=lca(x,y);
    	if(now!=y) {
    		add1(now,now,-1);
    		int tmp1=dep[x]-dep[now];
    		int id1=go_up(x,tmp1-1);
    		add1(id1,x,-1);
    		tmp1=dep[y]-dep[now];
    		int id2=go_up(y,tmp1-1);
    		add1(id2,y,-1);
    	} else {
    		add1(y,x,-1);
    	}
    }
    int u;
    void FIE()
    {
    	freopen("overlap1.in","r" ,stdin);
    	freopen("op.out","w",stdout);
    }
    int main() {
    	//FIE();
    	n=R();
    	Q=R();
    	u=R();
    	int x,y,z;
    	for(int i=1; i<n; i++) {
    		x=R();
    		y=R();
    		add(x,y);
    		add(y,x);
    	}
    	dfs1(1,0);
    	dfs2(1,0,1);
    	while(Q--) {
    		x=R();
    		z=R();
    		y=R();
    		ch1(x,z);
    		int ans=ch2(y,z);
    		print(ans);
    		era(x,z);
    	}	
     fwrite(pbuf,1,pf-pbuf,stdout);
    }
    

    下面是倍增的想法:
    注意到终点是固定的
    那么也就是说x或者y或者z 应该是与另一个点 到一个汇点 然后再一起到终点的

    官方题解:
    问题实际上是问树上一个点到另外两点路径的重合长度
    树上三点,或是呈一条链的形式,或是存在一个中心,使得中心到三点之间的路径不相交。如下图,上方的两种情况是A、B、C点存在中心O,下方两种情况是A、B、C点在一条链上。对于呈一条链的形式,我们不妨将三个点中,位于中间的那个点称为三个点的中心,如此一来,我们要求的答案实际上是中心到B点的距离。那么,如何求中心呢?通过观察上图,我们发现,中心一定是A、B、C点中两点的LCA。并且,通过进一步观察,我们可以发现,中心是A、B、C点两两的LCA中,深度最大的点。所以,我们只需求出中心,在求出中心到B点的距离即可解决本题。该算法的时间复杂度是O(N+Q)或O((N+Q)*LogN)的。

    这题很像紧急集合那道题
    询问树上的一个点到其他三个点的距离之和最短
    两两lca 深度最大的即为答案

    或者也可以分类讨论
    假如z在xy与lca的路径之外 答案为lca到z的路径距离
    假如z在xy与lca的路径之中 答案为lca到z的路径距离 答案为在这条路径上的点与z的lca到z的距离 可以通过dfs序列和倍增来实现

    读题
    文件
    心态
    空间
    时间分配

  • 相关阅读:
    Docker配置samba共享
    阿里云SSL 免费证书申请方法
    linux centos7 关闭防火墙的方法
    PHP 面向对象的特性 抽象类和接口
    详解mixphp的依赖注入控制反转
    swoole mixphp swoolefor热更新使用方法
    nginx ab并发测试 apr_socket_recv: Connection refused (111
    PHP golang java 并发测试
    php.ini 添加的模块没更新的解决方法
    关于golang的未来的道路
  • 原文地址:https://www.cnblogs.com/OIEREDSION/p/11627555.html
Copyright © 2011-2022 走看看