2019-ICPC-南京网络赛 A,B,F,H

Contest:https://www.jisuanke.com/contest/3004?view=challenges

为什么感觉好写的题这么少呢。。

A. The beautiful values of the palace(规律+二维偏序问题)

题目链接:https://nanti.jisuanke.com/t/41298

题目大意:有一个n*n的宫殿,蛇形序列,每个点都有自己的价值。只有m个点有真实值。p次查询。对于每次查询,找到里面所有值的数位之和。

思路:首先要有一个映射关系,即将(x,y)对应的真实值求出。经过观察我们容易发现规律,洛谷上有一个螺旋矩阵的题,换过来就好了:https://www.luogu.org/problem/P2239。然后就是计算答案了。

离线处理,很容易发现就是一个二位偏序问题。

对询问点和有效点进行排序,枚举右端点,是一个宫殿就更新线段树,否则查询。

ACCode:

#include<stdlib.h>
#include<string.h>
#include<stdio.h>
#include<time.h>
#include<math.h>
// srand((unsigned)time(NULL));rand();
      
#include<map>
#include<set>
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<string>
#include<fstream>
#include<iostream>
#include<algorithm>
 
#define ll long long
#define PII pair<int,int>
#define PLL pair<ll,ll>
#define clean(a,b) memset(a,b,sizeof(a))
using namespace std;
      
const int MAXN=1e5+10;
const int MAXM=1e6+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll MOD=1e9+7;
const double PI=acos(-1.0);
const double EPS=1.0e-8;
//unsigned register
// ios::sync_with_stdio(false)

struct SegTree{
	struct Node{
		int l,r,len;
		ll Sum;
	};
	Node Tree[MAXM<<2];
	
	void PushUp(int rt){
		Tree[rt].Sum=Tree[rt<<1].Sum+Tree[rt<<1|1].Sum;
	}
	void Build(int l,int r,int rt){
		Tree[rt].l=l;Tree[rt].r=r;
		Tree[rt].Sum=0;
		if(l==r) return ;
		int mid=(l+r)>>1;
		Build(l,mid,rt<<1);Build(mid+1,r,rt<<1|1);
	}
	void Update(int pos,ll val,int rt){
		if(pos==0) return ;
		if(Tree[rt].l==Tree[rt].r){
			Tree[rt].Sum+=val;
			return ;
		}
		if(pos<=Tree[rt<<1].r) Update(pos,val,rt<<1);
		else Update(pos,val,rt<<1|1);
		PushUp(rt);
	}
	ll Query(int ql,int qr,int rt){
		if(ql>qr) return 0;
		if(ql<=Tree[rt].l&&Tree[rt].r<=qr) return Tree[rt].Sum;
		if(qr<=Tree[rt<<1].r) return Query(ql,qr,rt<<1);
		else if(ql>=Tree[rt<<1|1].l) return Query(ql,qr,rt<<1|1);
		else return 1ll*Query(ql,qr,rt<<1)+Query(ql,qr,rt<<1|1);
	}
	void Show(int rt){
		printf("l=%d r=%d Sum=%lld\n",Tree[rt].l,Tree[rt].r,Tree[rt].Sum);
		if(Tree[rt].l==Tree[rt].r) return ;
		Show(rt<<1);Show(rt<<1|1);
	}
};
struct Point{
	int i,j,val,opt;
	friend int operator < (Point a,Point b){
		if(a.i!=b.i) return a.i<b.i; 
		if(a.j!=b.j) return a.j<b.j;
		return a.opt<b.opt;
	}
};
SegTree Seg;
Point Dots[MAXN],Suf[MAXM];
PII Ask[MAXN][2];
ll Ans[MAXM];
map<PII,int> MP;

ll GetVal(int n,int i,int j){
	ll ans;
    ll mi=min(i,min(j,min(n-i+1,n-j+1)));
    if(i<=j) ans=1ll*mi*(1ll*4*(n-1)-4*mi)+1ll*10*mi-4*n-3+i+j;
    else ans=1ll*mi*(4*n-4*mi)+1ll*2*mi+1-i-j;//模拟过程
    return ans;
}
ll Work(int n,int i,int j){
	ll x=GetVal(n,n+1-i,n+1-j),ans=0;
	while(x){
		ans+=x%10;
		x/=10;
	}return ans;
}
int main(){
	int T;scanf("%d",&T);
	while(T--){
		MP.clear();
		int n,m,q;scanf("%d%d%d",&n,&m,&q);
		for(int i=1;i<=m;++i){
			int x,y;scanf("%d%d",&x,&y);
			Dots[i].i=x;Dots[i].j=y;Dots[i].val=Work(n,x,y);
		}
		for(int i=1;i<=q;++i){
			int x1,x2,y1,y2;scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
			Ask[i][0]=make_pair(x1,y1);Ask[i][1]=make_pair(x2,y2);
		}
		Seg.Build(1,MAXM,1);
		int sum=m+4*q;
		for(int i=1;i<=m;++i){//共m个有效点 
			int x=Dots[i].i,y=Dots[i].j;
			Suf[i].i=x;Suf[i].j=y;Suf[i].val=Dots[i].val;Suf[i].opt=1;
		}
		for(int i=1;i<=q;++i){//共q个询问点 
			Suf[i+m].i=Ask[i][0].first-1;Suf[i+m].j=Ask[i][0].second-1;Suf[i+m].opt=2;
			Suf[i+m+q].i=Ask[i][0].first-1;Suf[i+m+q].j=Ask[i][1].second;Suf[i+m+q].opt=2;
			Suf[i+m+2*q].i=Ask[i][1].first;Suf[i+m+2*q].j=Ask[i][0].second-1;Suf[i+m+2*q].opt=2;
			Suf[i+m+3*q].i=Ask[i][1].first;Suf[i+m+3*q].j=Ask[i][1].second;Suf[i+m+3*q].opt=2;
		}sort(Suf+1,Suf+sum+1);//将询问点排序 
//		for(int i=1;i<=sum;++i) printf("i=%d j=%d val=%lld opt=%d\n",Suf[i].i,Suf[i].j,Suf[i].val,Suf[i].opt);
		for(int i=1;i<=sum;++i){
			int x=Suf[i].i,y=Suf[i].j,val=Suf[i].val,opt=Suf[i].opt;
			if(opt==1){//是一个宫殿 
				Seg.Update(y,val,1);
			}
			else{//是一个起点||其他询问点||终点,刷新答案后不用换 
				Ans[i]=Seg.Query(1,y,1);
				MP[make_pair(x,y)]=i;
//				printf("x=%d y=%d Ans=%lld\n",x,y,Ans[MP[make_pair(x,y)]]);
			}
		}
		//Ans=[x2][y2]-[x2][y1-1]-[x1-1][y2]+[x1-1][y1-1];
		for(int i=1;i<=q;++i){
			PII str=Ask[i][0],ed=Ask[i][1];
			ll ans=Ans[MP[make_pair(ed.first,ed.second)]]-Ans[MP[make_pair(ed.first,str.second-1)]]-Ans[MP[make_pair(str.first-1,ed.second)]]+Ans[MP[make_pair(str.first-1,str.second-1)]];
//			printf("%lld - %lld - %lld + %lld = %lld\n",Ans[MP[make_pair(ed.first,ed.second)]],Ans[MP[make_pair(ed.first,str.second-1)]],Ans[MP[make_pair(str.first-1,ed.second)]],Ans[MP[make_pair(str.first-1,str.second-1)]],ans);
			printf("%lld\n",ans);
		}
	}
}

B. super_log(欧拉降幂)

题目链接:https://nanti.jisuanke.com/t/41299

数论队友的题:https://blog.csdn.net/henucm/article/details/100290033

F. Greedy Sequence(静态主席树)

题目链接:https://nanti.jisuanke.com/t/41303

题目大意:给出1个长度为n的序列A,每个数字都是唯一的&&1<=A[i]<=n

找到n个序列,满足第i个序列B[1]=i,每个序列单调不增(由于元素唯一,所以也就是单调减)

每次选择的元素在A数组中的位置相差不能大于k。

找出最大的字典序序列

思路:区间最大的<=B[j-1]的值,明显的静态 主席树

ACCode:

#include<stdlib.h>
#include<string.h>
#include<stdio.h>
#include<time.h>
#include<math.h>
// srand((unsigned)time(NULL));rand();
      
#include<map>
#include<set>
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<string>
#include<fstream>
#include<iostream>
#include<algorithm>
 
#define ll long long
#define PII pair<int,int>
#define PLL pair<ll,ll>
#define clean(a,b) memset(a,b,sizeof(a))
using namespace std;
      
const int MAXN=1e5+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll MOD=1e9+7;
const double PI=acos(-1.0);
const double EPS=1.0e-8;
//unsigned register
// ios::sync_with_stdio(false)

struct ChairTree{
	int Rt[MAXN<<5],Lc[MAXN<<5],Rc[MAXN<<5],Sum[MAXN<<5];
	int NodeCnt;
	
	void Build(int l,int r,int rt){
		rt=++NodeCnt;
		if(l==r) return ;
		int mid=(l+r)>>1;
		Build(l,mid,Lc[rt]);Build(mid+1,r,Rc[rt]);
	}
	int Modify(int pos,int l,int r,int rt){
		int Nrt=++NodeCnt;
		Lc[Nrt]=Lc[rt];Rc[Nrt]=Rc[rt];Sum[Nrt]=Sum[rt]+1;
		if(l==r) return Nrt;
		int mid=(l+r)>>1;
		if(pos<=mid) Lc[Nrt]=Modify(pos,l,mid,Lc[Nrt]);
		if(pos>mid) Rc[Nrt]=Modify(pos,mid+1,r,Rc[Nrt]);
		return Nrt;
	}
	int Query(int ql,int qr,int l,int r,int k){
	//[ql,qr]种找最后一个<=k的元素 
		if(l==r) return l;
		int xl=Sum[Lc[qr]]-Sum[Lc[ql]],xr=Sum[Rc[qr]]-Sum[Rc[ql]];
		int mid=(l+r)>>1;
//		printf("xl=%d xr=%d l=%d r=%d mid=%d k=%d\n",xl,xr,l,r,mid,k);
		//[l,mid]中存在这样的元素 
		int ans=INF32;
		if(mid>=k){//只会出现在[l,mid]
			if(xl) ans=Query(Lc[ql],Lc[qr],l,mid,k);
			else return ans;
		}
		else{// mid<k
		//[l,mid]和[mid+1,r]都可能出现
			if(xr) ans=Query(Rc[ql],Rc[qr],mid+1,r,k);
			if(ans!=INF32) return ans;
			if(xl) ans=Query(Lc[ql],Lc[qr],l,mid,k);
			return ans;
		}
	}
	void Intt(int l,int r){
		NodeCnt=0;
		Build(l,r,Rt[0]);
	}
	void Update(int pos,int l,int r,int i){
		Rt[i]=Modify(pos,l,r,Rt[i-1]);
	}
	int Ans(int ql,int qr,int l,int r,int k){//查找最大的<=r的元素 
		return Query(Rt[ql-1],Rt[qr],l,r,k);
	}
};
ChairTree CT;
int A[MAXN],Vis[MAXN];
int Ans[MAXN];
int n,k;

void DFS(int pos){
	int val=A[pos];
	if(Ans[val]) return ;
	int mi=max(1,pos-k),mx=min(n,pos+k);//查询[mi,mx]的最大的<A[pos]元素 
//	printf("pos=%d val=%d [%d,%d] \n",pos,val,mi,mx);
	int res;
	if(val==1) res=INF32;
	else res=CT.Ans(mi,mx,1,n,A[pos]-1);
//	printf("res=%d\n",res);
	if(res==INF32){
		Ans[val]=1;//当前没有更小的了 
//		printf("Ans[%d]=%d\n",val,Ans[val]);
	}
	else{
		DFS(Vis[res]);//更新更小的 
		Ans[val]=Ans[res]+1;//resi是可以选择的元素 
//		printf("Ans[%d]=%d\n",val,Ans[val]);
	}
}
int main(){
	int T;scanf("%d",&T);
	while(T--){
		clean(Ans,0); 
		scanf("%d%d",&n,&k);
		for(int i=1;i<=n;++i){
			scanf("%d",&A[i]);
			Vis[A[i]]=i;
		}CT.Intt(1,n);
		for(int i=1;i<=n;++i) CT.Update(A[i],1,n,i);
		for(int i=1;i<=n;++i) DFS(i);
		printf("%d",Ans[1]);
		for(int i=2;i<=n;++i) printf(" %d",Ans[i]);printf("\n");
	}
}

 H. Holy Grail(最短路签到)

题目链接:https://nanti.jisuanke.com/t/41305

题目大意:给出n个点,m条边的有向图,有负边权但没有负权回路,向图中添加6条边,每次添加边的时候都要保证不会构成负环。输入添加边的最小边权。

思路:添加的最小边权就是t->s 的最短路,因为如果添加之后,出现了负环,说明t->s之前存在一条更短的路线。所以必定是t->s的最短路。

ACCode:

#include<stdlib.h>
#include<string.h>
#include<stdio.h>
#include<time.h>
#include<math.h>
// srand((unsigned)time(NULL));rand();

#include<map>
#include<set>
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<string>
#include<fstream>
#include<iostream>
#include<algorithm>
 
#define ll long long
#define PII pair<int,int>
#define PLL pair<ll,ll>
#define clean(a,b) memset(a,b,sizeof(a))
using namespace std;
      
const int MAXN=5e2+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll MOD=1e9+7;
const double PI=acos(-1.0);
const double EPS=1.0e-8;
//unsigned register
// ios::sync_with_stdio(false)

struct Edge1{
	ll v,val,nxt;
	Edge1(ll _v=0,ll _val=0,ll _nxt=0){
		v=_v;val=_val;nxt=_nxt;
	}
};
Edge1 Edge[MAXN<<2];
int Head[MAXN],Ecnt;
ll Dis[MAXN];
int n,m;

void AddEdge(int u,int v,int val){
	Edge[Ecnt]=Edge1(v,val,Head[u]);
	Head[u]=Ecnt++;
}
void Dijkstra(int str){
	clean(Dis,INF64);Dis[str]=0;
	priority_queue<PLL,vector<PLL>,greater<PLL> > que;que.push(make_pair(0,str));
	while(que.size()){
		PLL u=que.top();que.pop();
		if(Dis[u.second]<u.first) continue ;
		for(int i=Head[u.second];i+1;i=Edge[i].nxt){
			int v=Edge[i].v;
			if(Dis[v]>Dis[u.second]+Edge[i].val){
				Dis[v]=Dis[u.second]+Edge[i].val;
				que.push(make_pair(Dis[v],v));
			}
		}
	}
}
int main(){
	int T;scanf("%d",&T);
	while(T--){
		scanf("%d%d",&n,&m);
		clean(Head,-1);Ecnt=0;
		for(int i=1;i<=m;++i){
			ll u,v,val;scanf("%lld%lld%lld",&u,&v,&val);
			AddEdge(u,v,val);
		}
		for(int i=1;i<=6;++i){
			int s,t;scanf("%d%d",&s,&t);
			Dijkstra(t);
			ll ans=Dis[s];ans=-ans;
			AddEdge(s,t,ans);
			printf("%lld\n",ans);
		}
	}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值