【C++】JOISC 2020 Day3原题+翻译+解析+代码

T1 Constellation3

原题

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

链接

LOJ-3274
UOJ-504
vjudge

翻译

题目描述

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

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

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

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

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

输入格式

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

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

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

接下来的 M M 行,每行三个整数 X i , Y i , C i X_i,Y_i,C_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 % 的数据, 1 N , M 200000 1≤N,M≤200000 ,保证:

  • 1 A i N ( 1 i N ) 1≤A_i≤N(1≤i≤N)
  • 1 X j , Y j N ( 1 j M ) 1≤X_j,Y_j≤N(1≤j≤M)
  • 1 C j 1 0 9 ( 1 j M ) 1≤C_j≤10^9(1≤j≤M)
  • A X j < Y j ( 1 j M ) A_{X_j}<Y_j(1≤j≤M)
  • ( X j , Y j ) ( X k , Y k ) ( 1 j < k M ) (X_j,Y_j)≠(X_k,Y_k)(1≤j<k≤M)

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

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

解析

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

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

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

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

考虑把笛卡尔树建成一个树形关系。
如果在 x x 这里选了一个 y y ,选 y y 就相当于覆盖了 x x x x 的一个祖先 z z ( a [ z ] < = y a[z]<=y a [ f a [ z ] ] > y a[fa[z]]>y )。
可以倍增求出 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 个员工, M M 棵苹果树种在湖岸。湖的周长为 L L 米。

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

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

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

输入格式

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

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

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

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

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

输出格式

输出共 Q Q 行,第 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 N + M L 1 0 9 N+M≤L≤10^9 1 C 1 0 9 1≤C≤10^9 1 Q 2 × 1 0 5 1≤Q≤2×10^5 ,保证:

  • 0 A i < L ( 1 i N ) 0≤A_i<L(1≤i≤N)
  • A i < A i + 1 ( 1 i N 1 ) A_i<A_i+1(1≤i≤N−1)
  • 0 B j < L ( 1 j M ) 0≤B_j<L(1≤j≤M)
  • B j < B j + 1 ( 1 j M 1 ) B_j<B_j+1(1≤j≤M−1)
  • A i B j ( 1 i N , 1 j M ) A_i≠B_j(1≤i≤N,1≤j≤M)
  • 1 V k N ( 1 k Q ) 1≤V_k≤N(1≤k≤Q)
  • 1 T k 1000000000000000000 = 1 0 18 ( 1 k Q ) 1≤T_k≤1000000000000000000=10^{18}(1≤k≤Q)

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

子任务编号 附加限制 分值
1 N , M , Q 3000 N,M,Q≤3000 5
2 T k 1015 T_k≥1015 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
v 2 = T 1 s [ y ] v_2=T_1−s[y]
那么贡献就是: [ v 1 > = v 2 ] ( ( v 1 v 2 ) l e n + 1 ) [v1>=v2]∗(⌊(v1−v2)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 个町,编号为 0 0 N 1 N−1 。Anthony 居住在 0 0 号町。总共有 M M 条路,编号为 0 0 M 1 M−1 。第 i i 条路连接编号为 U i U_i V i V_i 的町 ( U i V i U_i≠V_i ),每条路是双向的。保证不存在两条连接两个相同的町的道路,同时每个点可以直接或间接互相到达。

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

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

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

之后她会选择一条路去行动。注意除了上一次走来路,她仅能通过路上的标记来分辨其余的道路。她想尽量快地到达 0 0 号町。更准确地说,若起点至 0 0 号町最少需要经过 d d 条道路,那么她希望在经过不超过 d + B d+B 条边后就能到达 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 含义同题面。
    • U , V U,V 存储着所有的边, U [ i ] V [ i ] U[i] 和 V[i] 表示第i条路连接的街道 U i V i U_i 和 V_i

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

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

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

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

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

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

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

    如果 Catherine 未能在 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 。其中 S S 表示起点。
接下来 M M 行,每行两个数字 U i , V i U_i,V_i ,表示一条道路。

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

若程序运行时产生错误 [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
  • 子任务2 (2分): A = 4 , B = 0 A=4,B=0
  • 子任务3 (2分): A = 3 , B = 0 , M = N 1 A=3,B=0,M=N−1
  • 子任务4 (9分): 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
  • 子任务6 (71分): A = 2 , B = 12 , M = N 1 A=2,B=12,M=N−1
  • 子任务7 (9分): A = 2 , B = 6 , M = N 1 A=2,B=6,M=N−1

对于所有测试数据,满足 2 N 20000 , 1 M 20000 , 1 S < N 2≤N≤20000,1≤M≤20000,1≤S<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();
        }
    }
}

发布了108 篇原创文章 · 获赞 158 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/Ljnoit/article/details/105464641