[ICPC 2019 南京网络赛] 比赛题解

持续更新中…

A:The beautiful values of the palace

题意:

给你M个点,Q个矩形,每个点都有一个价值,求每个矩形点价值和

题目分析:

首先我们根据N的值和坐标可以O1的得出每个点的价值,这样就转化成了求一个二维矩阵前缀和的问题,由于我们开不了那么大的空间,我们就把第一维X排序,第二维Y扔进树状数组查询前缀和即可,把每个询问拆成四个点询问前缀和矩阵和,然后就可以得出大矩阵的答案了。

代码:

#include 
#include 
#include 
#include 
#define int long long
const int maxm=1e6+100;
const int N=1e6;
struct node{
	int x,y,id,tag;
}a[maxm];
int sum[maxm],ans[maxm];
int n,m,w,cnt,t;
inline int lowbit(int x){return x&(-x);}
inline void ins(int x,int val){for(int i=x;i<=N;i+=lowbit(i)) sum[i]+=val;}
inline int ask(int x){int res=0;for(int i=x;i;i-=lowbit(i)) res+=sum[i];return res;}
inline bool comp(node p,node q){return (p.xq.tag));}
inline int cal(int x,int y)
{
    int layer=std::min(std::min(x, y),n-std::max(x, y)+1);
    if((layer<<1)>n) return n*n;
    int st=n*n-(n-(layer<<1)+2)*(n-(layer<<1)+2)+1;
    if (x>=y) return st+((n-layer)<<1)+2-x-y;
    return st+((n-(layer<<1)+1)<<1)+x+y-(layer<<1);
}
inline int split(int x)
{
	int res=0;
	while(x)
	{
		res+=x%10;
		x/=10;
	}
	return res;
}
inline void work()
{
	scanf("%lld%lld%lld",&n,&m,&w);
	cnt=0;
	memset(sum,0,sizeof(sum));
	for(int i=1,x,y;i<=m;i++)
	{
	   scanf("%lld%lld",&x,&y);
	   a[++cnt]=node{x,y,split(cal(x,y)),2};	
	}
	for(int i=1,x1,y1,x2,y2;i<=w;i++)
	{
		scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);
		ans[i]=0;
		a[++cnt]=node{x2,y2,i,1};
		a[++cnt]=node{x2,y1-1,i,-1};
		a[++cnt]=node{x1-1,y2,i,-1};
		a[++cnt]=node{x1-1,y1-1,i,1};
	}
	std::sort(a+1,a+cnt+1,comp);
	for(int i=1;i<=cnt;i++)
	{
		if(a[i].tag==2) ins(a[i].y,a[i].id);
		else ans[a[i].id]+=a[i].tag*ask(a[i].y);
	}
	for(int i=1;i<=w;i++) printf("%lld\n",ans[i]);
}
signed main()
{
	scanf("%lld",&t);
	for(int i=1;i<=t;i++) work();
	return 0;
}

B:super log

题意:

求 a ^ a ^ a ^ (…) ^ a 共 b 个a%P的值

题目分析:

欧拉降幂就好了

代码:

#include 
#include 
#define int long long
const int N=1000000;
int phi[N+10],prime[N+10],mark[N+10];
int a,b,p,t,tot;
void getphi()
{
    phi[1]=1;
    for(int i=2;i<=N;i++)
     {
        if(!mark[i])
        {
            prime[++tot]=i;
            phi[i]=i-1;
        }
        for(int j=1;j<=tot&&i*prime[j]<=N;j++)
        {
            mark[i*prime[j]]=1;
            if(!(i%prime[j]))
             {
                phi[i*prime[j]]=phi[i]*prime[j];
                break;
             }
            else phi[i*prime[j]]=phi[i]*(prime[j]-1);
        }
     }
}
inline int fastpow(int x,int y,int mod)
{
	int ans=1;
	while(y)
	{
		if(y%2) ans=(ans*x)%mod;
		x=(x*x)%mod;
		y/=2; 
	}
	return ans;
}
int slove(int a,int b,int p)
{
	if(p==1) return 0;
    if(b==0) return 1;
    int d=slove(a,b-1,phi[p]);
    if(d

F:Greedy Sequence

题意:

太长了懒得说

题目分析:

对于每个值,他下面的值是一定的,我们只需要预处理出每个值下面连接的值,然后在这个图上就可以把每个值序列的长度跑出来了。
我们需要查询区间小于一个值的最大值,用主席树就能实现了。

代码:

#include 
#include 
#include 
#include 
#include 
#include 
const int maxm=1e5+100;
int n,k;
int val[maxm],ans[maxm];
int root[maxm];
bool in[maxm];
std::vector  edge[maxm];
std::queue  dl;
struct tree{
    int sum[maxm*20],ls[maxm*20],rs[maxm*20];
    int sz;
    void insert(int &now,int pre,int l,int r,int ind)
    {
        now=++sz;
        ls[now]=ls[pre],rs[now]=rs[pre],sum[now]=sum[pre]+1;
        if(l>=r) return;
        int mid=(l+r)>>1;
        ind<=mid?insert(ls[now],ls[pre],l,mid,ind):insert(rs[now],rs[pre],mid+1,r,ind);
    }
    int ask_rank(int now,int pre,int l,int r,int ind)
    {
        int nowsum=sum[now]-sum[pre];
        if(r<=ind) return nowsum;
        int mid=(l+r)>>1;
        if(mid+1<=ind) return ask_rank(ls[now],ls[pre],l,mid,ind)+ask_rank(rs[now],rs[pre],mid+1,r,ind);
        else return ask_rank(ls[now],ls[pre],l,mid,ind);
    }
    int find(int now,int pre,int l,int r,int kth)
    {
        if(l>=r) return l;
        int nowsum=sum[ls[now]]-sum[ls[pre]];
        int mid=(l+r)>>1;
        if(kth<=nowsum) return find(ls[now],ls[pre],l,mid,kth);
        else return find(rs[now],rs[pre],mid+1,r,kth-nowsum);
    }
}st;
inline int read()
{
    int x=0,w=1;
    char ch=0;
    while(ch<'0'||ch>'9')
    {
        if(ch=='-') w=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=(x<<3)+(x<<1)+ch-'0';
        ch=getchar();
    }
    return x*w;
}
inline void work()
{
    st.sz=0;
    n=read(),k=read();
    for(int i=1;i<=n;i++) val[i]=read(),ans[i]=0,in[i]=0,edge[i].clear();
    for(int i=1;i<=n;i++) st.insert(root[i],root[i-1],1,n,val[i]);
    for(int i=1;i<=n;i++)
    {
        int ql=std::max(1,i-k);
        int qr=std::min(n,i+k);
        int rank=st.ask_rank(root[qr],root[ql-1],1,n,val[i]);
        if(rank!=1)
        {
            int poi=st.find(root[qr],root[ql-1],1,n,rank-1);
            edge[poi].push_back(val[i]);
            in[val[i]]=1;
        } 
    }
    for(int i=1;i<=n;i++) if(!in[i]) dl.push(i),ans[i]=1;
    while(!dl.empty())
    {
        int now=dl.front();
        dl.pop();
        for(int i=0;i

你可能感兴趣的:(题目分析)