2018 ICPC Shenyang G - Best ACMer Solves the Hardest Problem

做题一定要把计算复杂度算明白,其次就是空间复杂度
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}\)为半径,作圆,把圆上的每个点的权值加起来,输出答案
本题有多组数据,且强制在线
其中\(1\le k\le 10^7,\sum n,\sum m\le 10^6,0\le x,y\le 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:\n",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\n",ans);
                lst=ans;
            }
        }
        for(int i=1;i<=cnt;i++)
            vis[qx[i]][qy[i]]=val[qx[i]][qy[i]]=0;
        cnt=0;
    }
}
posted @ 2021-03-06 19:06  ssdfzhyf  阅读(51)  评论(0编辑  收藏  举报