zoukankan      html  css  js  c++  java
  • noip模拟测试19

    这次考试,发挥不是很好,首先看了看三道题,1,2,3按顺序开题,看T1题面,首先我理解了半天,才明白这个图是左上角是(1,1),我刚开始一直把左下角当成(1,1)来处理,跟样例对不上,然后我就想到了差分,但是我不会利用差分数组求值,就放弃了这个想法,(结果正解就是差分。。。)我先打了一个暴力,又特判了一个特殊性质,但是判错了。
    然后是T2,这题我当时不太明白,打暴搜打假了,如果有两种选择,那么我们要选最优的决策再*2,这道题利用状压的思想再加上记忆化搜索就可以过。T3,这道题我在考场上连暴力也没打出来,有时间的原因,还有思路的原因,这道题也是一个记忆话搜索,下面我进行题目讲解:

    T1 u

    思路,二维差分数组,考虑维护一个竖着的差分数组s1,和一个斜着的差分数组 s2,每次修改,我们都只需要修改差分数组两边的值,举个例子,假设现在给出的四个数 r,c,l,s, 那么我们只需要让 s1[r][c]+=m,s1[r+l][c]-=m,
    s2[r][c+1]-=m,s2[r+l][c+l+1]+=m,其实自己手模一下就可以理解
    代码如下:

    #include<bits/stdc++.h>
    #define int long long
    #define re register int
    #define lc rt<<1
    #define rc rt<<1|1
    #define mid ((l+r)>>1)
    #define iv inline void
    #define ii inline int
    #define D double
    using namespace std;
    const int N=1e4+10;
    int n,q,r,c,l,s;
    int s1[N][N],s2[N][N];
    ii read()
    {
       int x=0,f=1;
       char ch=getchar();
       while(ch<'0'||ch>'9')
       {
       	if(ch=='-')
       		f=0;
       	ch=getchar();
       }
       while(ch>='0'&&ch<='9')
       {
       	x=(x<<1)+(x<<3)+(ch^48);
       	ch=getchar();
       }
       return (f)?x:(-x);
    }
    signed main()
    {
       n=read();
       q=read();
       for(re i=1;i<=q;i++)
       {
       	r=read();
       	c=read();
       	l=read();
       	s=read();
       	s1[r][c]+=s;
       	if(c+1<=n)
       		s2[r][c+1]-=s;
       	if(r+l<=n)
       	{
       		s1[r+l][c]-=s;
       		if(c+l+1<=n)
       			s2[r+l][c+l+1]+=s;
       	}
       }
       long long out=0; 
       for(re i=1;i<=n;i++)
       {
       	long long ans=0;
       	for(re j=1;j<=n;j++)
       	{
       		s1[i][j]+=s1[i-1][j];
       		s2[i][j]+=s2[i-1][j-1];
       		ans+=s1[i][j]+s2[i][j];
       		out^=ans;
       	}
       }
       printf("%lld\n",out);
    }
    
    

    T2 v

    思路:其实理解了题面后,这道题就是一个非常暴力的记忆化搜索,利用状压的思想暴力枚举每个状态最后取max,就是最优策略最大的期望值,这里面的序列更新操作比较妙,最后注意小的范围利用数组,大的范围利用map存储就可以过了
    代码如下;

    
    
    #include<bits/stdc++.h>
    #define int long long
    #define re register int
    #define lc rt<<1
    #define rc rt<<1|1
    #define mid ((l+r)>>1)
    #define iv inline void
    #define ii inline int
    #define D double
    using namespace std;
    map<int,double>f[31];
    double dp[24][1<<23];
    int n,k;
    char s[50];
    ii read()
    {
       int x=0,f=1;
       char ch=getchar();
       while(ch<'0'||ch>'9')
       {
       	if(ch=='-')
       		f=0;
       	ch=getchar();
       }
       while(ch>='0'&&ch<='9')
       {
       	x=(x<<1)+(x<<3)+(ch^48);
       	ch=getchar();
       }
       return (f)?x:(-x);
    }
    inline double dfs(int sta,int p)
    {
       if(p==n-k)
       	return 0;
       if(p<=23&&dp[p][sta]!=-1.00)
       	return dp[p][sta];
       if(p>23&&f[p].find(sta)!=f[p].end())
       	return f[p][sta];
       int l=(p>>1);
       int co,co1,co2,to1,to2;
       double sum=0.00000000;
       for(re i=1;i<=l;i++)
       {
       	co1=sta>>i-1&1;
       	co2=sta>>p-i&1;
       	to1=sta>>1&~((1<<i-1)-1)|sta&((1<<i-1)-1);
       	to2=sta>>1&~((1<<p-i)-1)|sta&((1<<p-i)-1);
       	sum+=2*max(dfs(to1,p-1)+co1,dfs(to2,p-1)+co2);
       }
       if(p&1)
       {
       	co=(p+1)>>1;
       	co1=sta>>(co-1)&1;
       	to1=sta>>1&~((1<<co-1)-1)|sta&((1<<co-1)-1);
       	sum+=dfs(to1,p-1)+co1;
       }
       return p>23?f[p][sta]=sum/(double)p:dp[p][sta]=sum/(double)p;
    }
    signed main()
    {
       n=read();
       k=read();
       scanf("%s",s);
       int sta=0;
       for(re i=n-k+1;i<=min(n,23ll);i++)
       {
       	for(re j=0;j<=(1<<i);j++)
       		dp[i][j]=-1.00;
       }
       for(re i=1;i<=n;i++)
       {
       	if(s[i-1]=='W')
       		sta|=(1<<(n-i));
       }
       printf("%.10lf\n",dfs(sta,n));
    }
    
    

    T3 w

    思路:考虑最后翻转的边集 S,最小操作数为 {V, S} 中奇数度数的点的一半,最小操作总长为 |S|。树形 dp 即可,dp[i][0/1] 记录以 i 为根的子树内,i 与父亲之间的边是否翻转,最少的奇度数点数、此时最小总长度;
    那么 设 w1为儿子翻转总数为奇数的情况,w2为儿子翻转总数为偶数的情况
    dp[i][1]=min((w1.c1,w1.c2+1),(w2.c1+1,w2.c2+1)).
    dp[i][0]=min((w1+1,c2),(w2.c1,w2.c2))
    代码如下:

    
    
    #include<bits/stdc++.h>
    //#define int long long
    #define re register int
    #define lc rt<<1
    #define rc rt<<1|1
    #define mid ((l+r)>>1)
    #define iv inline void
    #define ii inline int
    #define D double
    using namespace std;
    const int N=1e5+10;
    const int INF=1e9;
    int n,a,b,c,d,tot;
    int to[N<<1],next[N<<1],head[N<<1],col[N<<1];
    struct Node
    {
    	int c1,c2;
    	Node friend operator + (Node a,Node b)
    	{
    		return (Node){a.c1+b.c1,a.c2+b.c2};
    	}
    	bool friend operator < (Node a,Node b)
    	{
    		return a.c1==b.c1?a.c2<b.c2:a.c1<b.c1;
    	}
    }f[N][2];
    Node min(Node x,Node y)
    {
    	if(x<y)	return x;
    	return y;
    }
    ii read()
    {
    	int x=0,f=1;
    	char ch=getchar();
    	while(ch<'0'||ch>'9')
    	{
    		if(ch=='-')
    			f=0;
    		ch=getchar();
    	}
    	while(ch>='0'&&ch<='9')
    	{
    		x=(x<<1)+(x<<3)+(ch^48);
    		ch=getchar();
    	}
    	return (f)?x:(-x);
    }
    iv add(int x,int y,int z)
    {
    	to[++tot]=y;
    	next[tot]=head[x];
    	head[x]=tot;
    	col[tot]=z;
    }
    iv dfs(int st,int fa,int tp)
    {
    	Node w1=(Node){INF,INF},w2=(Node){0,0},u1,u2;
    	for(re i=head[st];i;i=next[i])
    	{
    		int p=to[i];
    		if(p==fa)
    			continue;
    		dfs(p,st,col[i]);
    	//	u1=w2+f[p][1];
    		u1=min(w2+f[p][1],w1+f[p][0]);
    		u2=min(f[p][1]+w1,f[p][0]+w2);
    		w1=u1;
    		w2=u2;
    	}
    	if(tp==1||tp==2)
    		f[st][1]=min((Node){w1.c1,w1.c2+1},(Node){w2.c1+1,w2.c2+1});
    	else
    		f[st][1]=(Node){INF,INF};
    	if(tp==0||tp==2)
    		f[st][0]=min((Node){w1.c1+1,w1.c2},(Node){w2.c1,w2.c2});
    	else
    		f[st][0]=(Node){INF,INF};
    }
    signed main()
    {
    	n=read();
    	for(re i=1;i<n;i++)
    	{
    		a=read();
    		b=read();
    		c=read();
    		d=read();
    		if(d==2)
    			c=2;
    		else
    			c=(c!=d)?1:0;
    		add(a,b,c);
    		add(b,a,c);
    	}
    	dfs(1,0,2);
    	printf("%d %d",f[1][0].c1/2,f[1][0].c2);
    }
    
    
  • 相关阅读:
    flex布局
    cookie设置、获取、删除
    使用Object对象的toString()方法自定义判断数据类型方法
    git使用汇总
    闭包和面向对象
    闭包
    java8之一文彻底弄懂lambda表达式
    正确理解MESI协议
    二叉树中的节点删除-----按照最底层最右边的节点收缩
    按层次插入二叉树
  • 原文地址:https://www.cnblogs.com/WindZR/p/15029550.html
Copyright © 2011-2022 走看看