zoukankan      html  css  js  c++  java
  • 2019年8月8日(NOIP模拟赛DAY2)

    NOIP18年好难T_T~~~

    prob1:旅行

    60分的部分分肯定都会做,现在就是看剩下的40分怎么转成那60分的情况。

    那40分情况是(n=m),很明显是一个基环树,根据题目性质,肯定有一条边没跑,那么就枚举边,一条条删,再用60分的方法跑,得到答案。

    时间复杂度(O(n^2)):

    #include<iostream>
    #include<cstdio>
    #include<vector>
    #include<algorithm>
    using namespace std;
    #define in read()
    #define fur(i,a,b) for(int i=a;i<=b;i++)
    #define jinitaimei signed
    inline int read()
    {
    	int x=0;
    	char ch=getchar();
    	for(;!isalnum(ch);ch=getchar());
    	for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
    	return x;
    }
    const int xx=5e3+10;
    vector <int> e[xx];
    bool vis[xx],viss[xx],to[xx];
    int n,m,pre[xx],delx,dely,u[xx],v[xx],ans[xx],tmp[xx],all=0;
    inline void dfs1(int g)
    {
    	vis[g]=true;
    	printf("%d ",g);
    	int tp;
    	do
    	{
    		tp=6e3;
    		fur(i,0,(int)e[g].size()-1)
    		{
    			if(vis[e[g][i]]) continue;
    			tp=min(tp,e[g][i]);
    		}
    		if(tp<6e3) dfs1(tp);
    	}while(tp<6e3);
    }
    inline void dfs2(int g)
    {
    	vis[g]=true;
    	tmp[++all]=g;
    	fur(i,0,(int)e[g].size()-1)
    	{
    		if(vis[e[g][i]]) continue;
    		if(e[g][i]==delx&&g==dely) continue;
    		if(e[g][i]==dely&&g==delx) continue;
    		dfs2(e[g][i]);
    	}
    }
    jinitaimei main()
    {
    	n=in;m=in;
    	fur(i,1,m)
    	{
    		u[i]=in,v[i]=in;
    		e[u[i]].push_back(v[i]);
    		e[v[i]].push_back(u[i]);
    	}
    	if(n-1==m) dfs1(1);
    	else
    	{
    		if(n==5000) m=m*2/3;
    		fur(i,1,n) sort(e[i].begin(),e[i].end()),ans[i]=6e3;
    		fur(i,1,m)
    		{
    			delx=u[i];
    			dely=v[i];
    			all=0;
    			fur(j,1,n) vis[j]=false;
    			dfs2(1);
    			bool change=false;
    			if(all<n) continue;
    			fur(j,1,n)
    			{
    				if(ans[j]!=tmp[j])
    				{
    					change=ans[j]>tmp[j];
    					break;
    				}
    			}
    			if(change&&all==n) fur(j,1,n) ans[j]=tmp[j];
    		}
    		fur(j,1,n) printf("%d ",ans[j]);
    	}
    	printf("
    ");
    	return 0;
    }  
    

    prob2:填数游戏

    考场上懵逼的我只推出了(n=1&n=2)的规律。

    首先要明确两个性质:(1.)矩阵中每条对角线(本文对角线均默认为从左下到右上的对角线)上的数都是单调不增的。(2.)当有两个点对((x,y-1))((x-1,y))上填的数相同时,以((x,y))为左上端点,((m,n))为右下端点的矩阵中的每条对角线上的数都是相同的。

    这两个性质的满足是使矩阵合法的充要条件。

    有性质推出结论(大力模拟):(1.)(Ans(n,m)=Ans(m,n)),由此可以使(n)总不大于(m),故下文中的(n)恒不大于(m)(2.)(Ans(n=1,2,3,m))的通项公式;(3.)(n=m)(n+1=m)(Ans(n,m))的通项公式;(4.)(n>=4land m>=n+1)(Ans(n,m+1)=3* Ans(n,m))

    就一暴力模拟(+)数学,但相当之恶心。

    T_T……

    式子太恶心了……

    #include<bits/stdc++.h>
    using namespace std;
    #define fur(i,a,b) for(int i=a;i<=b;++i)
    #define fdr(i,a,b) for(int i=a;i>=b;--i)
    #define int long long
    const int mod=1e9+7;
    inline int power(int x,int k){int res=1;for(;k;x=x*x%mod,k>>=1) if(k&1) res=res*x%mod;return res;}
    signed main()
    {
    	int n,m;
    	cin>>n>>m;
    	if(n>m) swap(n,m);
    	if(n==1) cout<<power(2,m)<<endl;
    	if(n==2) cout<<4*power(3,m-1)%mod<<endl;
    	if(n==3) cout<<112*power(3,m-3)%mod<<endl;
    	if(n<=3) return 0;
    	if(n==m) cout<<(83*power(8,n)%mod+5*power(2,n+7)%mod)%mod*power(384,mod-2)%mod<<endl;
    	else cout<<(83*power(8,n)%mod+power(2,n+8))%mod*power(3,m-n-1)%mod*power(128,mod-2)%mod<<endl;
    	return 0;
    }
    

    prob3:保卫王国

    先贴(O(nm))的暴力吧:

    #include<iostream>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    using namespace std;
    #define in read()
    #define fur(i,a,b) for(int i=a;i<=b;i++)
    #define int long long
    #define jinitaimei signed
    inline int read()
    {
    	int x=0;
    	char ch=getchar();
    	for(;!isalnum(ch);ch=getchar());
    	for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
    	return x;
    }
    const int xx=1e6+10,inf=1e10;
    int f[xx][2],c[xx],a,x,b,y;
    vector<int>e[xx];
    bool flag;
    inline void dfs(int j,int fa)
    {
    	if(flag) return;
    	if(j!=a&&j!=b) f[j][0]=0,f[j][1]=c[j];
    	else if(j==a) f[j][x^1]=inf,f[j][x]=x==1?c[j]:0;
    	else if(j==b) f[j][y^1]=inf,f[j][y]=y==1?c[j]:0;
    	fur(i,0,(int)e[j].size()-1)
    	{
    		if(e[j][i]==fa) continue;
    		dfs(e[j][i],j);
    		if(flag) return;
    		if(f[j][0]!=inf) f[j][0]+=f[e[j][i]][1];
    		if(f[j][1]!=inf) f[j][1]+=min(f[e[j][i]][1],f[e[j][i]][0]);
    		if(f[j][1]==inf&&f[e[j][i]][1]==inf)
    		{
    			flag=true;
    			return;
    		}
    	}
    }
    jinitaimei main()
    {
    	int n=in,m=in;
    	char op[3];scanf("%s",op);
    	fur(i,1,n) c[i]=in;
    	fur(i,1,n-1)
    	{
    		int x=in,y=in;
    		e[x].push_back(y);
    		e[y].push_back(x);
    	}
    	fur(i,1,m)
    	{
    		a=in,x=in,b=in,y=in;
    		flag=false;
    		dfs(1,0);
    		if(flag||f[1][0]>=inf&&f[1][1]>=inf) puts("-1");
    		else printf("%lld
    ",min(f[1][1],f[1][0]));
    	}
    	return 0;
    }
    

    正解思路
    %倍增大贤者
    具体思路是这样的:
    建立两个正常(DP)数组(f,g),其中(f_{i,0/1})表示以(i)为根的子树(其中(i)不选((0))或选((1)))的最小代价,(g_{i,0/1})表示全树除以(i)为根的子树(其中(i)不选((0))或选((1)))的代价(该代价使全树有最优解)
    接下来就要建立倍增(DP)的主角(h)数组了,其中(h_{i,k,0/1,0/1})表示以(i)(2^k)级祖先为根的子树(其中(i)不选((0))或选((1)),以及(2^k)级祖先不选((0))或选((1)))除以(i)为根的子树的代价(该代价使全树有最优解)
    如此便可倍增跳转移状态了:注意要利用倍增(lca)的思想,先一方跳,再双方同时跳,一步步倍增上去
    时间复杂度(O((n+q)logn))
    详情见代码(话说码风有所改变):

    #include<bits/stdc++.h>
    using namespace std;
    
    #define ll long long
    
    inline int read()
    {
    	int x=0;char ch=getchar();
    	for(;!isalnum(ch);ch=getchar());
    	for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
    	return x;
    }
    
    const ll inf=1ll<<60;
    const int xx=1e5+10;
    ll c[xx],f[xx][2],g[xx][2],h[xx][20][2][2];
    int head[xx],nxt[xx<<1],to[xx<<1],all=0;
    int fa[xx][20],dep[xx],n,m;
    char none[5];
    
    inline void dfs1(int j)
    {
    	f[j][0]=0;f[j][1]=c[j];
    	for(register int v=head[j],u;v;v=nxt[v])
    	{
    		u=to[v];
    		if(u==fa[j][0]) continue;
    		dep[u]=dep[fa[u][0]=j]+1;
    		dfs1(u);
    		f[j][0]+=f[u][1];
    		f[j][1]+=min(f[u][1],f[u][0]);
    	}
    }
    inline void dfs2(int j)
    {
    	for(register int v=head[j],u;v;v=nxt[v])
    	{
    		u=to[v];
    		if(u==fa[j][0]) continue;
    		g[u][0]=g[j][1]+f[j][1]-min(f[u][1],f[u][0]);
    		g[u][1]=min(f[j][0]+g[j][0]-f[u][1],g[u][0]);
    		dfs2(u);
    	}
    }
    inline void init()
    {
    	dep[1]=1;
    	dfs1(1);dfs2(1);
    	for(register int i=1,j;i<=n;++i)
    	{
    		j=fa[i][0];
    		h[i][0][0][0]=inf;
    		h[i][0][1][0]=f[j][0]-f[i][1];
    		h[i][0][1][1]=h[i][0][0][1]=f[j][1]-min(f[i][1],f[i][0]);
    	}
    	for(register int k=1;k<=19;++k)
    		for(register int i=1,j;i<=n;++i)
    		{
    			j=fa[i][k-1];
    			fa[i][k]=fa[j][k-1];
    			for(register int p=0;p<=1;++p)
    				for(register int q=0;q<=1;++q)
    				{
    					h[i][k][p][q]=inf;
    					for(register int o=0;o<=1;++o)
    						h[i][k][p][q]=min(h[i][k][p][q],h[i][k-1][p][o]+h[j][k-1][o][q]);
    				}
    		}
    }
    
    inline void sol(int a,int x,int b,int y)
    {
    	ll tmp_a[2],tmp_b[2];
    	ll to_a[2],to_b[2];
    	to_a[0]=to_a[1]=to_b[0]=to_b[1]=inf;
    	to_a[x]=f[a][x];
    	to_b[y]=f[b][y];
    	for(register int k=19,j;~k;--k)
    		if(dep[j=fa[a][k]]>=dep[b])
    		{
    			tmp_a[0]=tmp_a[1]=inf;
    			for(register int p=0;p<=1;++p)
    				for(register int q=0;q<=1;++q)
    					tmp_a[p]=min(tmp_a[p],to_a[q]+h[a][k][q][p]);
    			to_a[0]=tmp_a[0];
    			to_a[1]=tmp_a[1];
    			a=j;
    		}
    	if(a==b)
    	{
    		printf("%lld
    ",to_a[y]+g[a][y]);
    		return;
    	}
    	for(register int k=19,i,j;~k;--k)
    		if((i=fa[a][k])!=(j=fa[b][k]))
    		{
    			tmp_a[0]=tmp_a[1]=tmp_b[0]=tmp_b[1]=inf;
    			for(register int p=0;p<=1;++p)
    				for(register int q=0;q<=1;++q)
    				{
    					tmp_a[p]=min(tmp_a[p],to_a[q]+h[a][k][q][p]);
    					tmp_b[p]=min(tmp_b[p],to_b[q]+h[b][k][q][p]);
    				}
    			to_a[0]=tmp_a[0],to_a[1]=tmp_a[1],a=i;
    			to_b[0]=tmp_b[0],to_b[1]=tmp_b[1],b=j;
    		}
    	int j=fa[a][0];
    	ll ans0=g[j][0]+f[j][0]-f[a][1]+to_a[1]-f[b][1]+to_b[1];
    	ll ans1=g[j][1]+f[j][1]-min(f[a][1],f[a][0])+min(to_a[1],to_a[0])-min(f[b][1],f[b][0])+min(to_b[1],to_b[0]);
    	printf("%lld
    ",min(ans0,ans1));
    }
    
    int main()
    {
    	n=read();m=read();
    	scanf("%s",none);
    	for(register int i=1;i<=n;++i) c[i]=read();
    	for(register int i=1,x,y;i<=n-1;++i)
    	{
    		x=read();y=read();
    		nxt[++all]=head[x];
    		to[head[x]=all]=y;
    		nxt[++all]=head[y];
    		to[head[y]=all]=x;
    	}
    	init();
    	for(register int i=1,a,b,x,y;i<=m;++i)
    	{
    		a=read();x=read();b=read();y=read();
    		if(dep[a]<dep[b]) swap(a,b),swap(x,y);
    		if((fa[a][0]==b)&&!x&&!y)
    		{
    			puts("-1");
    			continue;
    		}
    		sol(a,x,b,y);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Implementation of Message Receiver
    Data Model for Message Receiver
    SQL SERVER 批量生成编号
    修改hosts文件
    PHP-问题处理验证码无法显示出来
    PHP-问题处理Fatal error: Uncaught Error: Call to undefined function mb_strlen()
    PHP-问题处理Fatal error: Uncaught Error: Call to undefined function simplexml_load_file()
    10进制转33进制
    PHP-生成缩略图和添加水印图-学习笔记
    SQLServer地址搜索性能优化例子
  • 原文地址:https://www.cnblogs.com/ALANALLEN21LOVE28/p/11330522.html
Copyright © 2011-2022 走看看