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);
		}
	}
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章