zoukankan      html  css  js  c++  java
  • 2018 ICPC Shenyang G

    做题一定要把计算复杂度算明白,其次就是空间复杂度
    https://vjudge.net/contest/418609#problem/G
    题目大意:
    在平面上给定了n个点,然后有m个操作
    1.在(x,y)增加一个点,权值设为w(保证原来是空的)
    2.把(x,y)的点删掉(保证原来有点)
    3.以(x,y)为圆心,(sqrt{k})为半径,作圆,把圆上的每个点的权值+w
    4.以(x,y)为圆心,(sqrt{k})为半径,作圆,把圆上的每个点的权值加起来,输出答案
    本题有多组数据,且强制在线
    其中(1le kle 10^7,sum n,sum mle 10^6,0le x,yle 6000)
    本题给了12s,1GB内存,资源相当丰富,说明这个题可能做法比较暴力

    首先,平面上的点可以用二维数组存储,约60006000
    我们要存储点是否存在,以及点的权值,内存开销为6000
    6000*(4+1)=1.8e8B

    当一组数据的算法结束后,我们需要把每个存在的点的记录清空,复杂度为(O(n+m)),而不是将整个数组初始化

    操作3.4要求我们遍历所有距离(x,y)为(sqrt{k})的整数点
    一种方法是从(1)(sqrt{k})枚举(i),然后计算(sqrt{k-i^2})是不是整数,如果是整数,就查看一下((x+i,y+j))这个点
    这个做法不容易优化,单次查询需要(sqrt(k))
    考虑最多有(10^6)次操作,需要计算约(3e9)次,然而只有12s,时间吃紧,给30s可能会稳一些
    提交之后一般过不了,当然我不能排除有人使用计算机组成原理的知识进行玄学优化,说不定可以卡过

    考虑所有距离(x,y)为(sqrt{k})的整数点的个数可能不会达到3000多个,我做了一个测试
    从1到10000000遍历(k),看看(k=i^2+j^2)的整数解最多有几个,测试结果为192,远小于3000

    由于k最大是1e7,所以我们可以在3200的范围内枚举((i,j)),把枚举到的点加入到编号为k的链表或向量中,这样只要我们在查找k对应的线性表即可,里面的点对都是距离为k的整数点。
    预处理可能需要几秒,然后后面的询问部分的计算量不会超过(2e8),可以轻松通过

    代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    const int N=1e5+10;
    int cnt,qx[N*2],qy[N*2];
    int val[6005][6005];
    bool vis[6005][6005];
    struct pii
    {
    	int x,y;
    	pii operator =(const pii &b)
    	{
    		x=b.x;
    		y=b.y;
    		return *this; 
    	}
    	bool operator <(const pii &b)const
    	{
    		if(x!=b.x)return x<b.x;
    		
    		return y<b.y; 
    	}
    	bool operator ==(const pii &b)const
    	{
    		return (x==b.x)&&(y==b.y);
    	}
    	bool operator !=(const pii &b)const
    	{
    		return !(*this==b);
    	}
    };
    pii make_pair(int x,int y)
    {
    	pii re;
    	re.x=x;re.y=y;
    	return re;
    }
    vector<pii>vec[10000010];
    map<int,int> mp;
    pii tmp[10];
    int uni(pii a[],int n)
    {
    	int k=1;
    	for(int i=2;i<=n;i++)if(a[i]!=a[k])a[++k]=a[i];
    	return k;
    }
    int pre(int n)
    {
    	int m=sqrt(n);
    	if((m+1)*(m+1)<=n)m=m+1;
    	for(int i=0;i<=m;i++)
    	{
    		int all=n-i*i;
    		for(int j=i;j*j<=all;j++)
    		{
    			int now=i*i+j*j;
    			int cnt2=0;
    			tmp[++cnt2]=(make_pair(i,j));
    			tmp[++cnt2]=(make_pair(-i,j));
    			tmp[++cnt2]=(make_pair(i,-j));
    			tmp[++cnt2]=(make_pair(-i,-j));
    			
    			tmp[++cnt2]=(make_pair(j,i));
    			tmp[++cnt2]=(make_pair(j,-i));
    			tmp[++cnt2]=(make_pair(-j,i));
    			tmp[++cnt2]=(make_pair(-j,-i));
    			sort(tmp+1,tmp+cnt2+1);
    			cnt2=uni(tmp,cnt2);
    			for(int k=1;k<=cnt2;k++)vec[now].push_back(tmp[k]);
    		}
    	}
    }
    bool exist(int x,int y)
    {
    	if(x<1||x>6000||y<1||y>6000)return 0;
    	return vis[x][y];
    }
    int main()
    {
    	pre(10000000);
    
    	int t;
    	scanf("%d",&t);
        for(int c=1,n,m;c<=t;c++)
    	{
    		cnt=0;
            printf("Case #%d:
    ",c);
            
            scanf("%d%d",&n,&m);
            for(int i=1,x,y;i<=n;i++)
    		{
    			ll w;
                scanf("%d%d%lld",&x,&y,&w);
                vis[x][y]=1;
                val[x][y]=w;
                qx[++cnt]=x;
    			qy[cnt]=y;
            }
            ll lst=0;
            while(m--)
    		{
                int op,x,y;
    			int k,w;
                scanf("%d%d%d",&op,&x,&y);
                x=((x+lst)%6000)+1;
                y=((y+lst)%6000)+1;
                if(op==1)
    			{
                    scanf("%d",&w);
                    vis[x][y]=1;
                    val[x][y]=w;
                    qx[++cnt]=x;
    				qy[cnt]=y;
                }
                else if(op==2)
    			{
                    vis[x][y]=0;
    				val[x][y]=0;
                }
                else if(op==3)
    			{
                    scanf("%d%d",&k,&w);
                    for(int i=0;i<vec[k].size();i++)
    	            {
    	            	if(exist(x+vec[k][i].x,y+vec[k][i].y))val[x+vec[k][i].x][y+vec[k][i].y]+=w;
    				}
                }
                else
    			{
                    scanf("%d",&k);
                    ll ans=0;
                    for(int i=0;i<vec[k].size();i++)
    	            {
    	            	if(exist(x+vec[k][i].x,y+vec[k][i].y))
    					{
    						ans+=val[x+vec[k][i].x][y+vec[k][i].y];
    					}
    				}
                    printf("%lld
    ",ans);
                    lst=ans;
                }
            }
            for(int i=1;i<=cnt;i++)
                vis[qx[i]][qy[i]]=val[qx[i]][qy[i]]=0;
            cnt=0;
        }
    }
    
  • 相关阅读:
    基于vue的购物车清单
    圣杯布局和双飞翼布局
    正则限制input负数输入
    vue.js devtools图标不亮
    将二维数组转换成一维数组(基于reduce)
    基于PROMISE解决回调地狱问题
    封装AJAX库(参考JQ)
    for in和for of的区别
    抢购倒计时的实现
    git clone --depth=1 后获取其他分支
  • 原文地址:https://www.cnblogs.com/ssdfzhyf/p/14491699.html
Copyright © 2011-2022 走看看