【C++】JOISC 2020 Day3原题+翻译+解析+代码_template<typename t>inline void write(t x){-程序员宅基地

技术标签: JOISC  JOI  2020  【推荐专栏】成套题解  春令营  

T1 Constellation3

原题

CSDN下载:https://download.csdn.net/download/Ljnoit/12262096

链接

LOJ-3274
UOJ-504
vjudge

翻译

题目描述

JOI 君拍了一张 N × N N×N N×N 的星空图,将左起第 X X X 列,下起第 Y Y Y 行的像素点称为像素 ( X , Y ) (X,Y) (X,Y)

画面里有白色的大楼,黄色的星星,黑色的空格。第 i i i 列从最下方到自下数起第 A i A_i Ai 行都是白色的大楼。有 M M M 个星星,第 j j j 个星星位于像素点 ( X j , Y j ) (X_j,Y_j) (Xj,Yj)。此外,所有的像素点都是黑色。

若一个长方形区域可以称作星座,则满足以下条件:

  • 1.不含白色像素点。
  • 2.至少存在两个星星。

看厌了星座的 JOI 君要把一些黄色的星星涂成黑色,使得没有星座存在。将第 j j j 个星星涂成黑色会使照片的不自然度增加 C j C_j Cj,最初不自然度为 0 0 0。求不自然度的最小值。

输入格式

输入第一行为一个整数 N N N,表示地图的边长大小。

第二行为 N N N个整数 A 1 , … , A N A_1,…,A_N A1,,AN,描述如题目。

第三行为一个整数 M M M,表示星星的个数。

接下来的 M M M 行,每行三个整数 X i , Y i , C i X_i,Y_i,C_i Xi,Yi,Ci,即对第 i i i 个星星的描述。

输出格式

输出不自然度的最小值。

样例输入 1

5
1 3 4 2 3
3
1 5 3
4 3 2
2 4 2

样例输出 1

2

样例解释 1

在这里插入图片描述

可以发现把第三个星删了之后它就和一号构不成星座,且比删去一号花费少。

样例输入 2

7
5 6 2 3 6 7 6
5
7 7 5
3 3 7
3 7 10
1 7 6
4 7 8

样例输出 2

16

样例解释 2

删去三号和四号。

数据范围

对于 100 100 100% 的数据, 1 ≤ N , M ≤ 200000 1≤N,M≤200000 1N,M200000,保证:

  • 1 ≤ A i ≤ N ( 1 ≤ i ≤ N ) 1≤A_i≤N(1≤i≤N) 1AiN(1iN)
  • 1 ≤ X j , Y j ≤ N ( 1 ≤ j ≤ M ) 1≤X_j,Y_j≤N(1≤j≤M) 1Xj,YjN(1jM)
  • 1 ≤ C j ≤ 1 0 9 ( 1 ≤ j ≤ M ) 1≤C_j≤10^9(1≤j≤M) 1Cj109(1jM)
  • A X j < Y j ( 1 ≤ j ≤ M ) A_{X_j}<Y_j(1≤j≤M) AXj<Yj(1jM)
  • ( X j , Y j ) ≠ ( X k , Y k ) ( 1 ≤ j < k ≤ M ) (X_j,Y_j)≠(X_k,Y_k)(1≤j<k≤M) (Xj,Yj)=(Xk,Yk)(1j<kM)

详细子任务及附加限制如下表:

子任务编号 附加限制 分值
1 N , M ≤ 300 N,M≤300 N,M300 14
2 N , M ≤ 2000 N,M≤2000 N,M2000 21
3 无附加限制 65

解析

法一:
笛卡尔树+线段树合并

对于一个区间[li,ri],找到最高点a[x]。
这个区间只能有一个 > = a [ x ] >=a[x] >=a[x]的点。
暴力就是先建出笛卡尔树:
f [ i ] [ j ] f[i][j] f[i][j]表示 [ l i , r i ] [l_i,r_i] [li,ri]里选的最高点是j的最大和。
转移有: x x x这里选一个点 j 0 j_0 j0,左区间选一个 j 1 j_1 j1,右区间选一个 j 2 j_2 j2

可以一个接一个合并,复杂度 O ( n 2 ) O(n^2) O(n2)
用线段树合并优化一下就O( n l o g n n log n nlogn)

法二:
笛卡尔树+树状数组+dfs序

考虑把笛卡尔树建成一个树形关系。
如果在 x x x这里选了一个 y y y,选 y y y就相当于覆盖了 x x x x x x的一个祖先 z z z( a [ z ] < = y a[z]<=y a[z]<=y a [ f a [ z ] ] > y a[fa[z]]>y a[fa[z]]>y)。
可以倍增求出 z z z
问题变为一棵树上有若干祖先后代链,选出不相交的若干链,使权值和最大。
经典问题(不是祖先后代链也能做),只需要dfs序+树状数组实时维护一个点到根的dp值的和就差不多了。

代码

#pragma GCC optimize(3,"Ofast","inline")
#pragma G++ optimize(3,"Ofast","inline")

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <vector>

#define R                  register int
#define re(i,a,b)          for(R i=a; i<=b; i++)
#define ms(i,a)            memset(a,i,sizeof(a))
#define MAX(a,b)           (((a)>(b)) ? (a):(b))
#define MIN(a,b)           (((a)<(b)) ? (a):(b))

using namespace std;

typedef long long LL;
typedef pair<int,int> PII;

namespace IO {
    
	#include <cctype>

	template <typename T>
	inline void read(T &x){
    
		x=0; 
		char c=0; 
		T w=0;  
		while (!isdigit(c)) w|=c=='-',c=getchar();  
		while (isdigit(c)) x=x*10+(c^48),c=getchar();  
		if(w) x=-x;  
	}
	
	template <typename T>
	inline void write(T x) {
    
	    if(x<0) putchar('-'),x=-x;
	    if(x<10) putchar(x+'0');
	        else write(x/10),putchar(x%10+'0');
	}
	
	template <typename T>
	inline void writeln(T x) {
    
	    write(x);
	    putchar('\n');
	}
} 

using IO::read;
using IO::write;
using IO::writeln;

const int N=2e5+5;

struct Node {
    
	int f[N];
    
	int getfa(int x) {
    
        return x==f[x] ? x : f[x]=getfa(f[x]);
    }

	void init(int n) {
    
		for(int i=1; i<=n+1; i++) f[i]=i;
	}

	void merge(int x,int y) {
    
		int fx=getfa(x),fy=getfa(y);
		if(fx!=fy) f[fx]=fy;
	}
} f1,f2;

int n,m;
LL a[N],c[N];

vector <int> v[N];
vector <PII> s[N];

inline void add(int x,LL g) {
     
    while(x<=n+1) {
    
        c[x]+=g;
        x+=(x&(-x));
    }
}

inline LL ask(int x) {
    
    LL ret=0;
    while(x) {
    
        ret+=c[x]; 
        x-=(x&(-x));
    }
    return ret;
}

int main() {
    
	read(n);
	f1.init(n);
    f2.init(n);
	for(int i=1; i<=n; i++) {
    
        read(a[i]);
        v[a[i]].push_back(i);
    }
	read(m);
	int x,y,z;
	for(int i=1; i<=m; i++) {
    
		read(x); read(y); read(z);
		s[y].push_back(make_pair(x,z));
	}
	LL ans=0;
	for(int i=1; i<=n; i++) {
    
		for(auto r:s[i]) {
    
			LL tmp=ask(r.first);
			if(r.second>=tmp){
    
				ans+=tmp;
				add(f1.getfa(r.first)+1,r.second-tmp);
				add(f2.getfa(r.first),-r.second+tmp);
			}
			else ans+=r.second;
		}
		for(auto r:v[i]) {
    
			f1.merge(r,r-1);
			f2.merge(r,r+1);
		}
	}
	writeln(ans);
	return 0;
}

T2 Harvest

原题

CSDN下载:https://download.csdn.net/download/Ljnoit/12262096

链接

LOJ-3278
UOJ-508
vjudge

翻译

题目描述

IOI 庄园有 N N N 个员工, M M M 棵苹果树种在湖岸。湖的周长为 L L L 米。

一开始员工 i i i 位于从湖的最北端向顺时针方向前进 A i A_i Ai 米处,所有 A i A_i Ai 互异。苹果树 j j j 生长在从湖的最北端向顺时针方向前进 B j B_j Bj 米处,所有 B j B_j Bj 互异。

每棵苹果树最多长一个苹果,收获后 C C C 秒会长出一个新的。时刻 0 0 0 时,所有的苹果树上都有一个苹果。员工从时刻 0 0 0 开始从各自的地点以 1 m / s 1m/s 1m/s 的速度顺时针前进,遇到成熟的苹果就将其摘下(若到达时刚长出苹果,也要摘下),摘苹果的时间忽略不计。

现给出 Q Q Q 个询问,第 k k k 次询问员工 V k V_k Vk 在时刻 T k T_k Tk 结束时一共收获到几个苹果。

输入格式

输入第一行为四个整数 N , M , L , C N,M,L,C N,M,L,C,意义由题面所示。

第二行为 N N N 个整数 A 1 , … , A N A_1,…,A_N A1,,AN

第三行为 M M M 个整数 B 1 , … , B M B_1,…,B_M B1,,BM

第四行为一个整数 Q Q Q,即询问的数量。

接下来的 Q Q Q 行,每行两个整数 V i , T i V_i,T_i Vi,Ti

输出格式

输出共 Q Q Q 行,第 k k k 行输出一个整数为第 k k k 个问题的答案。

样例输入 1

3 2 7 3
1 4 6
0 5
3
1 7
2 3
3 8

样例输出 1

2
1
1

样例解释 1

在第 1 个时刻,员工 2 从第 2 棵苹果树上收获了苹果,员工 3 从第 1 棵苹果树上收获了苹果。

在第 3 个时刻,员工 2 到达了第 1 棵苹果树。但是因为那时树上没果子所以没收获。

在第 4 个时刻,员工 1 从第 2 棵苹果树上收获了苹果。

在第 6 个时刻,员工 1 从第 1 棵苹果树上收获了苹果,员工 3 到达了第 2 棵苹果树,但还是因为那时树上没果子所以没收获。

在第 8 个时刻,员工 2 从第 2 棵苹果树上收获了苹果,员工 3 到达了第 1 棵苹果树,但再一次因为那时树上没果子所以没收获。

到第 7 个时刻为止,员工 1 收获了 2 个苹果,故第一行输出 2。

样例输入 2

5 3 20 6
0 4 8 12 16
2 11 14
9
4 1932
2 93787
1 89
5 98124798
1 2684
1 137598
3 2
3 8375
4 237
样例输出 2
146
7035
7
7359360
202
10320
0
628
18

样例输入 3

8 15 217 33608
0 12 71 96 111 128 152 206
4 34 42 67 76 81 85 104 110 117 122 148 166 170 212
14
2 223544052420046341
3 86357593875941375
4 892813012303440034
1 517156961659770735
7 415536186438473633
6 322175014520330760
7 557706040951533058
6 640041274241532527
5 286263974600593111
8 349405886653104871
1 987277313830536091
5 989137777159975413
2 50689028127994215
7 445686748471896881
### 样例输出 3
33230868503053
3
5
1
123542793648997
8
165811220737767
8
7
1
1
7
7535161012043
132506837660717

数据范围

对于 100% 的数据, 1 ≤ N , M ≤ 2 × 1 0 5 1≤N,M≤2×10^5 1N,M2×105 N + M ≤ L ≤ 1 0 9 N+M≤L≤10^9 N+ML109 1 ≤ C ≤ 1 0 9 1≤C≤10^9 1C109 1 ≤ Q ≤ 2 × 1 0 5 1≤Q≤2×10^5 1Q2×105,保证:

  • 0 ≤ A i < L ( 1 ≤ i ≤ N ) 0≤A_i<L(1≤i≤N) 0Ai<L(1iN)
  • A i < A i + 1 ( 1 ≤ i ≤ N − 1 ) A_i<A_i+1(1≤i≤N−1) Ai<Ai+1(1iN1)
  • 0 ≤ B j < L ( 1 ≤ j ≤ M ) 0≤B_j<L(1≤j≤M) 0Bj<L(1jM)
  • B j < B j + 1 ( 1 ≤ j ≤ M − 1 ) B_j<B_j+1(1≤j≤M−1) Bj<Bj+1(1jM1)
  • A i ≠ B j ( 1 ≤ i ≤ N , 1 ≤ j ≤ M ) A_i≠B_j(1≤i≤N,1≤j≤M) Ai=Bj(1iN,1jM)
  • 1 ≤ V k ≤ N ( 1 ≤ k ≤ Q ) 1≤V_k≤N(1≤k≤Q) 1VkN(1kQ)
  • 1 ≤ T k ≤ 1000000000000000000 = 1 0 18 ( 1 ≤ k ≤ Q ) 1≤T_k≤1000000000000000000=10^{18}(1≤k≤Q) 1Tk1000000000000000000=1018(1kQ)

详细子任务及附加限制如下表:

子任务编号 附加限制 分值
1 N , M , Q ≤ 3000 N,M,Q≤3000 N,M,Q3000 5
2 T k ≥ 1015 T_k≥1015 Tk1015 20
3 无附加限制 75

解析

方法:基环树

考虑对每一个点求出fa[i]表示i取了一个果子后,下一个取这个果子的是谁。
因为每个点一条出边,所以是个基环内向树。
再处理一下每个果子第一次被谁吃,然后把每个果子的时间改为被第一个人吃的时间+到树根的时间。
用个线段树合并再查询一下得到树上的答案。
接着考虑环上的答案。
先破环为链,记一个前缀和数组s[x]表示从x走到1的答案,设环长是len。
x,y都是环上的点:
假设y子树里的一个果子到y的时间是T1,而x处有一个询问T2。
v 1 = T 2 − s [ x ] − [ x > y ] ∗ l e n v_1=T_2−s[x]−[x>y]*len v1=T2s[x][x>y]len
v 2 = T 1 − s [ y ] v_2=T_1−s[y] v2=T1s[y]
那么贡献就是: [ v 1 > = v 2 ] ∗ ( ⌊ ( v 1 − v 2 ) l e n ⌋ + 1 ) [v1>=v2]∗(⌊(v1−v2)len⌋+1) [v1>=v2]((v1v2)len+1)

代码

#pragma GCC optimize(3,"Ofast","inline")
#pragma G++ optimize(3,"Ofast","inline")

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <vector>

#define RI                 register int
#define re(i,a,b)          for(RI i=a; i<=b; i++)
#define ms(i,a)            memset(a,i,sizeof(a))
#define MAX(a,b)           (((a)>(b)) ? (a):(b))
#define MIN(a,b)           (((a)<(b)) ? (a):(b))

using namespace std;

typedef long long LL;
typedef pair<int,int> PII;

namespace IO {
    
	#include <cctype>

	template <typename T>
	inline void read(T &x){
    
		x=0; 
		char c=0; 
		T w=0;  
		while (!isdigit(c)) w|=c=='-',c=getchar();  
		while (isdigit(c)) x=x*10+(c^48),c=getchar();  
		if(w) x=-x;  
	}
	
	template <typename T>
	inline void write(T x) {
    
	    if(x<0) putchar('-'),x=-x;
	    if(x<10) putchar(x+'0');
	        else write(x/10),putchar(x%10+'0');
	}
	
	template <typename T>
	inline void writeln(T x) {
    
	    write(x);
	    putchar('\n');
	}
} 

using IO::read;
using IO::write;
using IO::writeln;

const int N=2e5+5;
const LL inf=2e18;

struct Node {
    
    int ch[2];
    int sum;
};

class sgt {
    
	public:
		Node t[20000000];
		int nodecnt;

		void init() {
    
			nodecnt=0;
		}

		int newnode() {
    
			int p=++nodecnt;
			t[p].ch[0]=t[p].ch[1]=t[p].sum=0;
			return p;
		}

		void insert(int &p,LL l,LL r,LL pos) {
    
			if(!p) p=newnode();
			t[p].sum++;
			if(l==r) return;
			LL mid=(l+r)>>1;
			if(pos<=mid) insert(t[p].ch[0],l,mid,pos);
			    else insert(t[p].ch[1],mid+1,r,pos);
		}

		int query(int p,LL l,LL r,LL ql,LL qr) {
    
			if(!p) return 0;
			if(ql<=l && r<=qr) return t[p].sum;
			LL mid=(l+r)>>1;
			int ret=0;
			if(ql<=mid) ret=query(t[p].ch[0],l,mid,ql,qr);
			if(qr>mid) ret+=query(t[p].ch[1],mid+1,r,ql,qr);
			return ret;
		}

		int merge(int x,int y) {
    
			if(!x || !y) return x|y;
			t[x].sum+=t[y].sum;
			t[x].ch[0]=merge(t[x].ch[0],t[y].ch[0]);
			t[x].ch[1]=merge(t[x].ch[1],t[y].ch[1]);
			return x;
		}
} T;

vector<int> pt1;
vector<int> stapple[N],t[N];
vector<pair<int,LL> > query[N];

int n,m,L,C,bans,bane;
int a[N],b[N],Q,fa[N],d[N],vis[N],rt[N];
LL dep[N],ans[N];

void dfs(int np) {
    
	vis[np]=1,pt1.push_back(np);
	for(int &x:stapple[np]) T.insert(rt[np],0,inf,x+dep[np]);
	for(int &x:t[np]) {
    
		if(np==bans && x==bane) continue;
		dep[x]=dep[np]+d[x];
        dfs(x);
        rt[np]=T.merge(rt[np],rt[x]);
	}
	for(auto &x:query[np]) 
        ans[x.first]=T.query(rt[np],0,2e18,dep[np],dep[np]+x.second);
}

void solve(int p) {
    
	T.init();
	int cx=p;
	pt1.clear();
	while(!vis[cx]) vis[cx]=1,cx=fa[cx];
	bans=fa[cx],bane=cx,dfs(cx);
	LL totlen=dep[bans]+d[cx];
	T.init();
	vector<LL> cur;
	for(int &x:pt1) for(int &y:stapple[x])
		cur.push_back(y+dep[x]+d[cx]+dep[bans]);
	sort(cur.begin(),cur.end());
	vector<pair<LL,LL> > c2;
	for(int i=bans; i; i=fa[i]) {
    
		for(auto &t:query[i])
            c2.push_back(make_pair(t.second+totlen+dep[i],t.first));
		if(i==bane) break;
	}
	sort(c2.begin(),c2.end());
	LL vl=0;
	int R=0;
	for(int i=0,j=0; i<(int)c2.size(); i++) {
    
		while(j<(int)cur.size() && cur[j]<=c2[i].first) {
    
			T.insert(R,0,totlen,cur[j]%totlen);
			vl+=cur[j]/totlen;
            j++;
		}
		ans[c2[i].second]-=vl;
		ans[c2[i].second]+=1LL*(c2[i].first/totlen)*T.query(R,0,totlen,0,c2[i].first%totlen);
		ans[c2[i].second]+=1LL*(c2[i].first/totlen-1)*T.query(R,0,totlen,c2[i].first%totlen+1,totlen);
	}
}

int main() {
    
    read(n);
    read(m);
    read(L);
    read(C);
	for(int i=1; i<=n; i++) {
    
        read(a[i]);
        a[i]=L-1-a[i];
    }
	for(int i=1; i<=m; i++) {
    
        read(b[i]);
        b[i]=L-1-b[i];
    }
	reverse(a+1,a+n+1);
    reverse(b+1,b+m+1);
	for(int i=1; i<=n; i++) {
    
		int nxt=(a[i]+C)%L;
		if(nxt>a[n])fa[i]=1,d[i]=L+a[1]-nxt+C;
		    else fa[i]=lower_bound(a+1,a+n+1,nxt)-a,d[i]=a[fa[i]]-nxt+C;
	}
	for(int i=1; i<=m; i++) {
    
		if(b[i]>a[n]) stapple[1].push_back(a[1]+L-b[i]);
		    else {
    
		    	int cur=lower_bound(a+1,a+n+1,b[i])-a;
		    	stapple[cur].push_back(a[cur]-b[i]);
		    }
	}
    read(Q);
	for(int i=1; i<=Q; i++) {
    
		int p;
        LL T;
        read(p);
        read(T);
		query[n+1-p].push_back(make_pair(i,T));
	}
	for(int i=1; i<=n; i++) t[fa[i]].push_back(i);
	for(int i=1; i<=n; i++) 
        if(!vis[i]) solve(i);
	for(int i=1; i<=Q; i++) writeln(ans[i]);
	return 0;
}

T3 Stray

原题

CSDN下载:https://download.csdn.net/download/Ljnoit/12262096

链接

UOJ-506

翻译

题目描述

这是一道通信题。

Anthony 是一只生活在 JOI 市的蚂蚁。JOI 市共有被划分为 N N N 个町,编号为 0 0 0 N − 1 N−1 N1。Anthony 居住在 0 0 0 号町。总共有 M M M 条路,编号为 0 0 0 M − 1 M−1 M1。第 i i i 条路连接编号为 U i U_i Ui V i V_i Vi 的町 ( U i ≠ V i U_i≠V_i Ui=Vi),每条路是双向的。保证不存在两条连接两个相同的町的道路,同时每个点可以直接或间接互相到达。

Catherine 是一只猫,也是 Anthony 的好朋友。她打算游览 JOI 市,但是她并不知道关于路的信息,所以经常迷路。于是,Anthony 打算事先在每条道路上都作上标记。标记共有 A A A 种,编号为 0 0 0 A − 1 A−1 A1

Catherine 现在到达了 JOI 市。当她不在 0 0 0 号町时,她会做如下事情:

  • 对于每种标记,她会统计当前所在的町连出去的道路中,除了她上一次走来的道路(若存在)之外,这种标记共出现了多少次。

之后她会选择一条路去行动。注意除了上一次走来路,她仅能通过路上的标记来分辨其余的道路。她想尽量快地到达 0 0 0 号町。更准确地说,若起点至 0 0 0 号町最少需要经过 d d d 条道路,那么她希望在经过不超过 d + B d+B d+B 条边后就能到达 0 0 0 号町。

你需要编写程序模拟 Anthony 摆放路标和 Catherine 探索 JOI 城的过程。

交互细节

你需要提交两个程序。

第一个程序为Anthony.cpp,它会模拟Anthony的摆放过程。需要包含头文件Anthony.h

  • std::vector<int> Mark(int N, int M, int A, int B, std::vector<int> U, std::vector<int> V)
    该程序会恰好在开始时调用一次。

    • 数字 N , M , A , B N,M,A,B N,M,A,B 含义同题面。
    • U , V U,V U,V存储着所有的边, U [ i ] 和 V [ i ] U[i] 和 V[i] U[i]V[i] 表示第i条路连接的街道 U i 和 V i U_i 和 V_i UiVi

    选手需要返回一个长度为 M M M 的数组 x x x,第 i i i 个元素 x i x_i xi 代表在第 i i i 条道路上的路标编号。

    x x x 长度不为 M M M,测评结果为 “Wrong Answer [1]”。若不满足 0 ≤ x i ≤ A − 1 0≤xi≤A−1 0xiA1,测评结果为 “Wrong Answer [2]”。

第二个程序为Catherine.cpp,它会模拟Catherine的探索过程。需要包含头文件Catherine.h

  • void Init(int A, int B)
    该程序会恰好在开始时调用一次。

    • 数字 A , B A,B A,B 含义同题面。
  • int Move(std::vector<int> y)
    该程序会在每次Catherine到达一个不是0的街道时调用。

    • y 是一个长度为A的数组,元素 yj 代表着所有与当前街道相连且不为她上一次走过的路(若存在)的路上标记 j 的出现次数。
    • 你需要返回一个整数 z z z,表示选择走的标记。需要满足 − 1 ≤ z ≤ A − 1 −1≤z≤A−1 1zA1。若不满足 − 1 ≤ z ≤ A − 1 −1≤z≤A−1 1zA1,测评结果为 “Wrong Answer [3]”。若 z = − 1 z=−1 z=1,表示Catherine原路返回,此时若Catherine未进行过任何操作,测评结果为 “Wrong Answer [4]”。若 0 ≤ z ≤ A − 1 0≤z≤A−1 0zA1,表示 Catherine 选择一条标记为 z 的边经过,此时若 y z = 0 yz=0 yz=0,测评结果为 “Wrong Answer [5]”。

    注意如果有多条可以选择的边,grader不一定会随机选择一条合法的出现行动。

    如果 Catherine 未能在 D + b D+b D+b 步内到达街道0,测评结果为 “Wrong Answer [6]”。

注意事项

选手程序可能会运用若干全局变量和子程序。为了防止多个文件变量重名或子程序重名带来的编译错误,请将所有全局变量和子程序定义在一个没有名字的 namespace 里。

如果在程序里使用 printf/scanf/cout/cin,会直接导致Wrong Answer 或者 Runtime Error。

最终测评时会将 Anthony 和 Catherine 的程序独立编译,因此不能共享全局变量。

编译与运行

grader.cpp, Anthony.cpp,Catherine.cpp,Anthony.h,Catherine.h放在同一文件夹下,在终端内运行如下命令

g++ -O2 -o grader grader.cpp Anthony.cpp Catherine.cpp

编译成功时会得到一个可执行文件grader
可执行文件从标准输入种读入以下内容:

第一行五个数字 N , M , A , B , S N,M,A,B,S N,M,A,B,S。其中 S S S表示起点。
接下来 M M M行,每行两个数字 U i , V i U_i,V_i Ui,Vi,表示一条道路。

可执行文件回想标准输出流输出以下内容。

若程序运行时产生错误 [1] 至 [5],则会输出形如 “Wrong Answer [1]” 的错误信息。
否则如果未在 N+B 步内到达街道1,输出 “Wrong Answer; Number of moves > N + B”.
否则按照 “Number of moves = 4” 的格式输出信息。

数据范围

  • 子任务1 (2分): A = 4 , B = 0 , M = N − 1 A=4,B=0,M=N−1 A=4,B=0,M=N1
  • 子任务2 (2分): A = 4 , B = 0 A=4,B=0 A=4,B=0
  • 子任务3 (2分): A = 3 , B = 0 , M = N − 1 A=3,B=0,M=N−1 A=3,B=0,M=N1
  • 子任务4 (9分): A = 3 , B = 0 A=3,B=0 A=3,B=0
  • 子任务5 (5分): A = 2 , B = 2 N , M = N − 1 , 6 ≤ N ≤ 500 A=2,B=2N,M=N−1,6≤N≤500 A=2,B=2N,M=N1,6N500
  • 子任务6 (71分): A = 2 , B = 12 , M = N − 1 A=2,B=12,M=N−1 A=2,B=12,M=N1
  • 子任务7 (9分): A = 2 , B = 6 , M = N − 1 A=2,B=6,M=N−1 A=2,B=6,M=N1

对于所有测试数据,满足 2 ≤ N ≤ 20000 , 1 ≤ M ≤ 20000 , 1 ≤ S < N 2≤N≤20000,1≤M≤20000,1≤S<N 2N20000,1M20000,1S<N

保证图联通且无重边无自环。

时间限制:2s
空间限制:1GB

解析

对于第一类子任务。我们只能走最短路。

考虑求出这张图的 BFS 树,显然,所有边要么是连接相邻两层的点(异层边),要么是连接同层的点(同层边)。

如果没有同层边,那么我们只要对于每一层的边做同一种标记,按 0,1,2 循环标记即可。因为这样的话,在某一个点上,即使有两种存在的标记,我们也可以确定哪一个是往上走的。

那么如果有了同层边,其实也很简单,只要做它下面的那一层的边的标记即可。

这样我们依旧可以确定哪一条边是向上的。

对于第二类子任务,只有两种标记,但图是一个树,而且允许多走六步。

我们先考虑把树划分为若干条链,如果一个点有至少两个儿子,那么称之为分叉点。我们希望标记能够满足:

对于每个分叉点,到父亲的边和到儿子的边的标记不同。
每一条链上都是 110010 的循环位移。
那么对于代码 B,它先走三步,如果中途走到非链的部分就直接确定了方向。否则,它还在链上,而且可以确定周围长度为 5 的子串的样子,这样的话,一定可以确定它是在往上走还是往下走,这样也确定了方向,而且最多多走 6 步。

代码

Anthony.cpp:

#include "Anthony.h"
#include <bits/stdc++.h>

using namespace std;

vector<int> Mark(int n,int m,int A,int B,vector<int> U,vector<int> V) {
    
    vector<int> dist(n, -1);
    vector<vector<int> > G(n);
    for (int i=0; i<m; i++) {
    
        G[U[i]].push_back(V[i]);
        G[V[i]].push_back(U[i]);
    }
    dist[0]=0;
    queue<int> que;
    que.push(0);
    while(!que.empty()) {
    
        int u=que.front(); 
        que.pop();
        for(int v:G[u]) {
    
            if(dist[v]==-1) {
    
                dist[v]=dist[u] + 1;
                que.push(v);
            }
        }
    }
    vector<int> ret(m);
    if(A>=3) {
    
        for(int i=0; i<m; i++) {
    
            ret[i]=min(dist[U[i]],dist[V[i]])%3;
        }
    } else {
    
        const int arr[6]={
    1,1,0,0,1,0};
        for (int i=0; i<n; i++) G[i].clear();
        for (int i=0; i<m; i++) {
    
            if(dist[U[i]]>dist[V[i]]) swap(U[i], V[i]);
            G[U[i]].push_back(i);
        }
        function<void(int, int)> dfs=[&](int u,int fr) {
    
            if((int)G[u].size() == 1) {
    
                int p;
                if(fr==-1 || ret[fr]==0) {
    
                    p = 0;
                } else {
    
                    p = 2;
                }
                while((int)G[u].size()==1) {
    
                    int i=G[u][0];
                    int v=V[i];
                    u=v;
                    fr=i;
                    ret[fr]=arr[p];
                    p=(p+1)%6;
                }
            }
            int c=(fr==-1 ? 1 : ret[fr]^1);
            for (int i:G[u]) {
    
                int v=V[i];
                ret[i]=c;
                dfs(v,i);
            }
        };
        dfs(0,-1);
    }
    return ret;
}

Catherine.cpp:

#include "Catherine.h"
#include <bits/stdc++.h>

using namespace std;

namespace {
    
    const int arr[6]={
    1,1,0,0,1,0};
    int A,on,fir,last;
    vector<int> vec;
    vector<int> cs;
    inline bool bad(vector<int> v) {
    
        vector<int> al;
        for(int i=0; i<6; i++) al.push_back(arr[i]);
        for(int i=0; i<6; i++) al.push_back(arr[i]);
        for(int i=0; i<8; i++) {
    
            int flag=1;
            for(int j=0; j<5; j++) if(al[i+j]!=v[j]) {
    
                flag=0;
                break;
            }
            if(flag) return true;
        }
        return false;
    }
}

void Init(int _A, int B) {
    
    A=_A;
    on=0;
    fir=1;
    last=-1;
}

int Move(vector<int> y) {
    
    if(A>=3) {
    
        int cc=0;
        for(int i=0; i<3; i++) cc+=(y[i]!=0 ? 1 : 0);
        if(cc==1) {
    
            if(y[0]) return 0;
                else if(y[1]) return 1;
                    else return 2;
        } else {
    
            if(y[0] && y[1]) return 0;
                else if(y[1] && y[2]) return 1;
                    else return 2;
        }
    } else {
    
        if(on) {
    
            if(y[0]==1 && y[1]!=1) return last=0;
                else if(y[0]!=1 && y[1]==1) return last=1;
                    else return last^=1;
        }
        if(fir) {
    
            fir=0;
            if(y[0]!=1 && y[1]!=1) {
    
                if(y[0]) last = 0;
                    else last = 1;
                y[last]--;
                cs=y;
                vec.push_back(last);
                return last;
            }
            if(y[0]==1) last=0;
                else last = 1;
            if(y[last^1]!=1) {
    
                on=1;
                return last;
            }
            y[last]--;
            cs=y;
            vec.push_back(last);
            return last;
        }
        if(y[0]!=1 && y[1]!=1) {
    
            on=1;
            return -1;
        }
        if(y[0]==1 && y[1]==1) {
    
            on=1;
            return last^=1;
        }
        if(y[0]>1) {
    
            on=1;
            return last=1;
        }
        if(y[1] >1) {
    
            on=1;
            return last=0;
        }
        if(vec.size()<3) {
    
            if(y[0]) last=0;
                else last=1;
            vec.push_back(last);
            return last;
        }
        vector<int> v;
        v.push_back(cs[0] ? 0 : 1);
        for(int i=0; i<3; i++) {
    
            v.push_back(vec[i]);
        }
        v.push_back(y[0] ? 0 : 1);
        on=1;
        if(bad(v)) {
    
            return -1;
        } else {
    
            return last=v.back();
        }
    }
}

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Ljnoit/article/details/105464641

智能推荐

oracle 12c 集群安装后的检查_12c查看crs状态-程序员宅基地

文章浏览阅读1.6k次。安装配置gi、安装数据库软件、dbca建库见下:http://blog.csdn.net/kadwf123/article/details/784299611、检查集群节点及状态:[root@rac2 ~]# olsnodes -srac1 Activerac2 Activerac3 Activerac4 Active[root@rac2 ~]_12c查看crs状态

解决jupyter notebook无法找到虚拟环境的问题_jupyter没有pytorch环境-程序员宅基地

文章浏览阅读1.3w次,点赞45次,收藏99次。我个人用的是anaconda3的一个python集成环境,自带jupyter notebook,但在我打开jupyter notebook界面后,却找不到对应的虚拟环境,原来是jupyter notebook只是通用于下载anaconda时自带的环境,其他环境要想使用必须手动下载一些库:1.首先进入到自己创建的虚拟环境(pytorch是虚拟环境的名字)activate pytorch2.在该环境下下载这个库conda install ipykernelconda install nb__jupyter没有pytorch环境

国内安装scoop的保姆教程_scoop-cn-程序员宅基地

文章浏览阅读5.2k次,点赞19次,收藏28次。选择scoop纯属意外,也是无奈,因为电脑用户被锁了管理员权限,所有exe安装程序都无法安装,只可以用绿色软件,最后被我发现scoop,省去了到处下载XXX绿色版的烦恼,当然scoop里需要管理员权限的软件也跟我无缘了(譬如everything)。推荐添加dorado这个bucket镜像,里面很多中文软件,但是部分国外的软件下载地址在github,可能无法下载。以上两个是官方bucket的国内镜像,所有软件建议优先从这里下载。上面可以看到很多bucket以及软件数。如果官网登陆不了可以试一下以下方式。_scoop-cn

Element ui colorpicker在Vue中的使用_vue el-color-picker-程序员宅基地

文章浏览阅读4.5k次,点赞2次,收藏3次。首先要有一个color-picker组件 <el-color-picker v-model="headcolor"></el-color-picker>在data里面data() { return {headcolor: ’ #278add ’ //这里可以选择一个默认的颜色} }然后在你想要改变颜色的地方用v-bind绑定就好了,例如:这里的:sty..._vue el-color-picker

迅为iTOP-4412精英版之烧写内核移植后的镜像_exynos 4412 刷机-程序员宅基地

文章浏览阅读640次。基于芯片日益增长的问题,所以内核开发者们引入了新的方法,就是在内核中只保留函数,而数据则不包含,由用户(应用程序员)自己把数据按照规定的格式编写,并放在约定的地方,为了不占用过多的内存,还要求数据以根精简的方式编写。boot启动时,传参给内核,告诉内核设备树文件和kernel的位置,内核启动时根据地址去找到设备树文件,再利用专用的编译器去反编译dtb文件,将dtb还原成数据结构,以供驱动的函数去调用。firmware是三星的一个固件的设备信息,因为找不到固件,所以内核启动不成功。_exynos 4412 刷机

Linux系统配置jdk_linux配置jdk-程序员宅基地

文章浏览阅读2w次,点赞24次,收藏42次。Linux系统配置jdkLinux学习教程,Linux入门教程(超详细)_linux配置jdk

随便推点

matlab(4):特殊符号的输入_matlab微米怎么输入-程序员宅基地

文章浏览阅读3.3k次,点赞5次,收藏19次。xlabel('\delta');ylabel('AUC');具体符号的对照表参照下图:_matlab微米怎么输入

C语言程序设计-文件(打开与关闭、顺序、二进制读写)-程序员宅基地

文章浏览阅读119次。顺序读写指的是按照文件中数据的顺序进行读取或写入。对于文本文件,可以使用fgets、fputs、fscanf、fprintf等函数进行顺序读写。在C语言中,对文件的操作通常涉及文件的打开、读写以及关闭。文件的打开使用fopen函数,而关闭则使用fclose函数。在C语言中,可以使用fread和fwrite函数进行二进制读写。‍ Biaoge 于2024-03-09 23:51发布 阅读量:7 ️文章类型:【 C语言程序设计 】在C语言中,用于打开文件的函数是____,用于关闭文件的函数是____。

Touchdesigner自学笔记之三_touchdesigner怎么让一个模型跟着鼠标移动-程序员宅基地

文章浏览阅读3.4k次,点赞2次,收藏13次。跟随鼠标移动的粒子以grid(SOP)为partical(SOP)的资源模板,调整后连接【Geo组合+point spirit(MAT)】,在连接【feedback组合】适当调整。影响粒子动态的节点【metaball(SOP)+force(SOP)】添加mouse in(CHOP)鼠标位置到metaball的坐标,实现鼠标影响。..._touchdesigner怎么让一个模型跟着鼠标移动

【附源码】基于java的校园停车场管理系统的设计与实现61m0e9计算机毕设SSM_基于java技术的停车场管理系统实现与设计-程序员宅基地

文章浏览阅读178次。项目运行环境配置:Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。项目技术:Springboot + mybatis + Maven +mysql5.7或8.0+html+css+js等等组成,B/S模式 + Maven管理等等。环境需要1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。_基于java技术的停车场管理系统实现与设计

Android系统播放器MediaPlayer源码分析_android多媒体播放源码分析 时序图-程序员宅基地

文章浏览阅读3.5k次。前言对于MediaPlayer播放器的源码分析内容相对来说比较多,会从Java-&amp;amp;gt;Jni-&amp;amp;gt;C/C++慢慢分析,后面会慢慢更新。另外,博客只作为自己学习记录的一种方式,对于其他的不过多的评论。MediaPlayerDemopublic class MainActivity extends AppCompatActivity implements SurfaceHolder.Cal..._android多媒体播放源码分析 时序图

java 数据结构与算法 ——快速排序法-程序员宅基地

文章浏览阅读2.4k次,点赞41次,收藏13次。java 数据结构与算法 ——快速排序法_快速排序法