zoukankan      html  css  js  c++  java
  • 8-23模拟赛解题报告

    新来Ag大佬,下午写了三小时成绩是我三倍(捂脸


    T1.淘淘种地

    题目大意:给出一个矩阵,每次选出一个子矩阵与一个权值,如果矩阵内权值与给出权值不同,则变成(-1),求最后有多少个数变成了(-1)

    本题有一个部分分,就是矩阵内权值只有(1)(2),也就是说只有两种情况,我们其实也可以看成(1)(0),这样就变成了一个比较直观的问题。

    我们可以发现,题目中要求的只是最后有多少个数变成了(-1),这就提醒我们可以最后一起统计答案,所以二维差分就变成了一个不错的选择。

    (0)(1)分成两部分计算,然后答案取并就好了。开两个数组,分别保存(0)(1)的差分值,最后前缀和统计答案,如果这个点(a_{ij}~xor~1)后的值的覆盖了这个位置的话,答案(+1)

    现在我们来看正解,通过运用上面的方法,我们想到把所有数二进制拆分,然后每一位进行一次上面的操作,最后答案取并就好了。时间复杂度为(O((nm+T)log{nm}))

    小结:

    解题关键:想到二进制拆分每一个数统计答案

    芝士点:差分

    不知道是我打炸了还是咋滴,总是TLE或者RE,没办法,只能贴一个(60)分代码了 (~

    #pragma GCC optimize(2)
    #include<bits/stdc++.h>
    #define re register
    using namespace std;
    const int N=1000005;
    inline int read()
    {
    	re int x=0,f=1;
    	re char ch=getchar();
    	for(;ch>'9'||ch<'0';ch=getchar())if(ch=='-')f*=-1;
    	for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<1)+(x<<3)+(ch^48);
    	return x*f;
    }
    int n,m,T,aa,vis[N][20][2],ans,a[N][20],mid;
    bool finvis[N];
    inline int to(int x,int y)
    {
    	if(x<1||y<1)return 0;
    	return (x-1)*m+y;
    }
    int main()
    {
    	scanf("%d%d%d",&n,&m,&T);
    	for(re int i=1;i<=n;i++)
    		for(re int j=1;j<=m;j++)
    		{
    			aa=read();
    			for(re int k=0;k<20;k++)
    			a[to(i,j)][k]=(aa&(1<<k));
    		}
    	for(re int i=1,type,x1,x2,y1,y2;i<=T;i++)
    	{
    		x1=read(),y1=read(),x2=read(),y2=read(),type=read();
    		for(re int j=0;j<20;j++)
    		{
    			mid=(type&(1<<j));
    			vis[to(x1,y1)][j][mid]++;
    			if(x2+1<=n&&y2+1<=m)vis[to(x2+1,y2+1)][j][mid]++;
    			if(x2+1<=n) vis[to(x2+1,y1)][j][mid]--;
    			if(y2+1<=m) vis[to(x1,y2+1)][j][mid]--;
    		}
    	}
    	for(re int i=1;i<=n;i++)
    		for(re int j=1;j<=m;j++)
    		{
    			mid=to(i,j);
    			for(re int k=0;k<20;k++)
    			{
    				vis[mid][k][0]+=vis[to(i-1,j)][k][0]+vis[to(i,j-1)][k][0]-vis[to(i-1,j-1)][k][0];
    				vis[mid][k][1]+=vis[to(i-1,j)][k][1]+vis[to(i,j-1)][k][1]-vis[to(i-1,j-1)][k][1];
    				if(vis[mid][k][a[mid][k]^1]>0){ans++;break;}
    			}
    		}
    	printf("%d",ans);
    	return 0;
    }
    

    T2.蓝蓝的数列

    题目大意:定义如下数列:

    [a_n=left{egin{aligned}0~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ n=1\a_{lfloorfrac{n}{2} floor}+(-1)^{frac{n(n+1)}{2}}~~~~nge 2end{aligned} ight. ]

    (sum_{i=1}^{n}left|a_i ight|)的值。


    考场上想了好久呀!(题目漏看了一个绝对值

    现在还不会,以后再来补吧,咕咕咕~~


    T3.树

    题目大意:给出一棵树,求所有包含节点(x)的联通块的权值和,一个连通块的权值定义为这个联通块的所有点的权值之积。支持操作为修改权值和改变一个节点的父亲。

    这题考场上毫无头绪,也是看题解才略懂一些。

    这题也是一道DP题,(f[u][i])为以(u)为根的子树中,包含根节点的联通块大小为(i)的权值和。(

    考虑到联通块大小最大为(10),所以我们可以更新每个点与其距离为(10)以内的祖先节点,每次递归计算答案。

    先是操作一,修改权值,其实我们可以将这个点对其祖先节点的贡献归零,再重新计算新的贡献。操作二的方式差不多,删去这个点对其原祖先节点的贡献,再重新计算对现在祖先节点的贡献,由于联通块大小最多为(c),更新一个节点的(f)需要(O(c^2)),所以每次删除和计算的时间复杂度为(O(c^3))

    又由于联通块的权值定义为点的乘积,所以我们可以重新定义运算符,使其变成卷积的形式就可以大大减小代码量 (可蒟蒻的我只会看题解写

    小结:

    解题关键:想到如何快速计算贡献

    芝士点:树形DP

    手起,码落:

    #include<bits/stdc++.h>
    #define re register
    #define mod 1000000007
    using namespace std;
    inline int read()
    {
    	re int x=0,f=1;
    	re char ch=getchar();
    	for(;ch>'9'||ch<'0';ch=getchar())if(ch=='-')f*=-1;
    	for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<1)+(x<<3)+(ch^48);
    	return x*f;
    }
    inline int Pow(long long x,int y)
    {
    	re long long sum=1;
    	for(;y;x=(x*x)%mod,y>>=1)
    		if(y&1)sum=(sum*x)%mod;
    	return sum;
    }
    const int N=200005;
    struct node{long long val[11];}e[N];
    node operator +(node a,node b)
    {
    	for(re int i=9;i>0;i--)
    		for(re int j=1;j+i<=10;j++)
    			a.val[i+j]=(a.val[i+j]+a.val[i]*b.val[j])%mod;
    	return a;
    }
    node operator -(node a,node b)
    {
    	for(re int i=1;i<=9;i++)
    		for(re int j=1;j+i<=10;j++)
    			a.val[i+j]=(a.val[i+j]+(mod-a.val[i])*b.val[j]%mod)%mod;
    	return a;
    }
    int n,m,fa[N];
    long long a[N];
    inline void dele(int x,int dep)
    {
    	if(x==1||dep==0)return ;
    	dele(fa[x],dep-1);
    	e[fa[x]]=e[fa[x]]-e[x];
    }
    inline void add(int x,int dep)
    {
    	if(x==1||dep==0)return ;
    	e[fa[x]]=e[fa[x]]+e[x];
    	add(fa[x],dep-1);
    }
    inline node query(int x,int y)
    {
    	if(x==1||y==0)return e[x];
    	return e[x]+(query(fa[x],y-1)-e[x]);
    }
    int main()
    {
    	n=read(),m=read();
    	for(re int i=1;i<=n;i++) a[i]=read(),e[i].val[1]=a[i];
    	for(re int i=2;i<=n;i++) fa[i]=read();
    	for(re int i=n;i>1;i--) e[fa[i]]=e[fa[i]]+e[i];
    	for(re int i=1,type,x,y;i<=m;i++)
    	{
    		type=read(),x=read(),y=read();
    		if(type==0) 
    		{
    			dele(x,10);
    			for(re int j=1;j<=10;j++)
    				e[x].val[j]=e[x].val[j]*Pow(a[x],mod-2)%mod*y%mod;
    			a[x]=y,add(x,10);
    		}
    		else if(type==1) 
    		{
    			dele(x,10),add(fa[x],9),fa[x]=y;
    			dele(fa[x],9),add(x,10);
    		}
    		else printf("%lld
    ",query(x,y).val[y]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    [转]更新到Android 3.0 虚拟机启动时窗口太大 的调整
    云 实例 之 http://www.salesforce.com/cn/
    [转]步步为营 .NET 代码重构学习笔记 一、为何要代码重构
    忽弃工资及周边 自我人生 需在付出中获得 必在实践中成长
    [转]Android开发中插入新的Activity
    [转]How to Create HTML5 Website and Page Templates for Visual Studio 2010
    MogileFS is an open source distributed filesystem
    [转] HTML 5 Intellisense for Visual Studio 2010 and 2008
    [转]eclipse android : A project with that name already exists in the workspace
    android 在manifest 中设置 多个Activity时的 默认 根 Activity
  • 原文地址:https://www.cnblogs.com/jkzcr01-QAQ/p/13574137.html
Copyright © 2011-2022 走看看