【C++】JOISC 2020 Day3原題+翻譯+解析+代碼

T1 Constellation3

原題

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

鏈接

LOJ-3274
UOJ-504
vjudge

翻譯

題目描述

JOI 君拍了一張 N×NN×N 的星空圖,將左起第 XX 列,下起第 YY 行的像素點稱爲像素 (X,Y)(X,Y)

畫面裏有白色的大樓,黃色的星星,黑色的空格。第 ii 列從最下方到自下數起第 AiA_i 行都是白色的大樓。有 MM 個星星,第 jj 個星星位於像素點 (Xj,Yj)(X_j,Y_j)。此外,所有的像素點都是黑色。

若一個長方形區域可以稱作星座,則滿足以下條件:

  • 1.不含白色像素點。
  • 2.至少存在兩個星星。

看厭了星座的 JOI 君要把一些黃色的星星塗成黑色,使得沒有星座存在。將第 jj 個星星塗成黑色會使照片的不自然度增加 CjC_j,最初不自然度爲 00。求不自然度的最小值。

輸入格式

輸入第一行爲一個整數 NN,表示地圖的邊長大小。

第二行爲 NN個整數 A1,,ANA_1,…,A_N,描述如題目。

第三行爲一個整數 MM,表示星星的個數。

接下來的 MM 行,每行三個整數 Xi,Yi,CiX_i,Y_i,C_i,即對第 ii 個星星的描述。

輸出格式

輸出不自然度的最小值。

樣例輸入 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

刪去三號和四號。

數據範圍

對於 100100% 的數據,1N,M2000001≤N,M≤200000,保證:

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

詳細子任務及附加限制如下表:

子任務編號 附加限制 分值
1 N,M300N,M≤300 14
2 N,M2000N,M≤2000 21
3 無附加限制 65

解析

法一:
笛卡爾樹+線段樹合併

對於一個區間[li,ri],找到最高點a[x]。
這個區間只能有一個>=a[x]>=a[x]的點。
暴力就是先建出笛卡爾樹:
f[i][j]f[i][j]表示[li,ri][l_i,r_i]裏選的最高點是j的最大和。
轉移有:xx這裏選一個點j0j_0,左區間選一個j1j_1,右區間選一個j2j_2

可以一個接一個合併,複雜度O(n2)O(n^2)
用線段樹合併優化一下就O(nlognn log n)

法二:
笛卡爾樹+樹狀數組+dfs序

考慮把笛卡爾樹建成一個樹形關係。
如果在xx這裏選了一個yy,選yy就相當於覆蓋了xxxx的一個祖先zz(a[z]<=ya[z]<=ya[fa[z]]>ya[fa[z]]>y)。
可以倍增求出zz
問題變爲一棵樹上有若干祖先後代鏈,選出不相交的若干鏈,使權值和最大。
經典問題(不是祖先後代鏈也能做),只需要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 莊園有 NN 個員工,MM 棵蘋果樹種在湖岸。湖的周長爲 LL 米。

一開始員工 ii 位於從湖的最北端向順時針方向前進 AiA_i 米處,所有 AiA_i 互異。蘋果樹 jj 生長在從湖的最北端向順時針方向前進 BjB_j 米處,所有 BjB_j 互異。

每棵蘋果樹最多長一個蘋果,收穫後 CC 秒會長出一個新的。時刻 00 時,所有的蘋果樹上都有一個蘋果。員工從時刻 00 開始從各自的地點以 1m/s1m/s 的速度順時針前進,遇到成熟的蘋果就將其摘下(若到達時剛長出蘋果,也要摘下),摘蘋果的時間忽略不計。

現給出 QQ 個詢問,第 kk 次詢問員工 VkV_k 在時刻 TkT_k 結束時一共收穫到幾個蘋果。

輸入格式

輸入第一行爲四個整數 N,M,L,CN,M,L,C,意義由題面所示。

第二行爲 NN 個整數 A1,,ANA_1,…,A_N

第三行爲 MM 個整數 B1,,BMB_1,…,B_M

第四行爲一個整數 QQ,即詢問的數量。

接下來的 QQ 行,每行兩個整數 Vi,TiV_i,T_i

輸出格式

輸出共 QQ 行,第 kk 行輸出一個整數爲第 kk 個問題的答案。

樣例輸入 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% 的數據,1N,M2×1051≤N,M≤2×10^5N+ML109N+M≤L≤10^91C1091≤C≤10^91Q2×1051≤Q≤2×10^5,保證:

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

詳細子任務及附加限制如下表:

子任務編號 附加限制 分值
1 N,M,Q3000N,M,Q≤3000 5
2 Tk1015T_k≥1015 20
3 無附加限制 75

解析

方法:基環樹

考慮對每一個點求出fa[i]表示i取了一個果子後,下一個取這個果子的是誰。
因爲每個點一條出邊,所以是個基環內向樹。
再處理一下每個果子第一次被誰吃,然後把每個果子的時間改爲被第一個人吃的時間+到樹根的時間。
用個線段樹合併再查詢一下得到樹上的答案。
接着考慮環上的答案。
先破環爲鏈,記一個前綴和數組s[x]表示從x走到1的答案,設環長是len。
x,y都是環上的點:
假設y子樹裏的一個果子到y的時間是T1,而x處有一個詢問T2。
v1=T2s[x][x>y]lenv_1=T_2−s[x]−[x>y]*len
v2=T1s[y]v_2=T_1−s[y]
那麼貢獻就是:[v1>=v2]((v1v2)len+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 市共有被劃分爲 NN 個町,編號爲 00N1N−1。Anthony 居住在 00 號町。總共有 MM 條路,編號爲 00M1M−1。第 ii 條路連接編號爲 UiU_iViV_i 的町 (UiViU_i≠V_i),每條路是雙向的。保證不存在兩條連接兩個相同的町的道路,同時每個點可以直接或間接互相到達。

Catherine 是一隻貓,也是 Anthony 的好朋友。她打算遊覽 JOI 市,但是她並不知道關於路的信息,所以經常迷路。於是,Anthony 打算事先在每條道路上都作上標記。標記共有 AA 種,編號爲 00A1A−1

Catherine 現在到達了 JOI 市。當她不在 00 號町時,她會做如下事情:

  • 對於每種標記,她會統計當前所在的町連出去的道路中,除了她上一次走來的道路(若存在)之外,這種標記共出現了多少次。

之後她會選擇一條路去行動。注意除了上一次走來路,她僅能通過路上的標記來分辨其餘的道路。她想盡量快地到達 00 號町。更準確地說,若起點至 00 號町最少需要經過 dd 條道路,那麼她希望在經過不超過 d+Bd+B 條邊後就能到達 00 號町。

你需要編寫程序模擬 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,BN,M,A,B 含義同題面。
    • U,VU,V存儲着所有的邊,U[i]V[i]U[i] 和 V[i] 表示第i條路連接的街道 UiViU_i 和 V_i

    選手需要返回一個長度爲 MM 的數組 xx,第 ii 個元素 xix_i 代表在第 ii 條道路上的路標編號。

    xx 長度不爲 MM,測評結果爲 “Wrong Answer [1]”。若不滿足 0xiA10≤xi≤A−1,測評結果爲 “Wrong Answer [2]”。

第二個程序爲Catherine.cpp,它會模擬Catherine的探索過程。需要包含頭文件Catherine.h

  • void Init(int A, int B)
    該程序會恰好在開始時調用一次。

    • 數字 A,BA,B 含義同題面。
  • int Move(std::vector<int> y)
    該程序會在每次Catherine到達一個不是0的街道時調用。

    • y 是一個長度爲A的數組,元素 yj 代表着所有與當前街道相連且不爲她上一次走過的路(若存在)的路上標記 j 的出現次數。
    • 你需要返回一個整數 zz,表示選擇走的標記。需要滿足 1zA1−1≤z≤A−1。若不滿足 1zA1−1≤z≤A−1,測評結果爲 “Wrong Answer [3]”。若 z=1z=−1,表示Catherine原路返回,此時若Catherine未進行過任何操作,測評結果爲 “Wrong Answer [4]”。若 0zA10≤z≤A−1,表示 Catherine 選擇一條標記爲 z 的邊經過,此時若 yz=0yz=0,測評結果爲 “Wrong Answer [5]”。

    注意如果有多條可以選擇的邊,grader不一定會隨機選擇一條合法的出現行動。

    如果 Catherine 未能在 D+bD+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,SN,M,A,B,S。其中SS表示起點。
接下來MM行,每行兩個數字 Ui,ViU_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=N1A=4,B=0,M=N−1
  • 子任務2 (2分):A=4,B=0A=4,B=0
  • 子任務3 (2分):A=3,B=0,M=N1A=3,B=0,M=N−1
  • 子任務4 (9分):A=3,B=0A=3,B=0
  • 子任務5 (5分):A=2,B=2N,M=N1,6N500A=2,B=2N,M=N−1,6≤N≤500
  • 子任務6 (71分):A=2,B=12,M=N1A=2,B=12,M=N−1
  • 子任務7 (9分):A=2,B=6,M=N1A=2,B=6,M=N−1

對於所有測試數據,滿足 2N20000,1M20000,1S<N2≤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();
        }
    }
}

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