1. 程式人生 > 其它 >[考試總結]noip模擬15

[考試總結]noip模擬15

這次不咕了。

首先發現這套題目十分毒瘤, \(T1\) 就沒有太大的思路。

結果最後也是暴力收場。。。

菜。

\(T1\;60pts\) 暴力居然還是挺高的,\(T2\) 莽了一個隨機化上去結果還是暴力分數。\(T3\)過於莽撞只打了一個垃得不能再垃的暴力結果只有 \(30pts\) ,結果賽後 \(set\) 直接撐到 \(60pts\)

掛了不少,主要還是欠考慮。

\(T1\) 主要就是在 \(60pts\) 的基礎之上把字首和優化加上,這樣的話就只用處理一個 \(\mathcal O(4000^2log(4000))\) 的預處理,因為常數還是比較小的,所以沒有什麼問題,完全可以跑動。

之後在詢問每一個問題的時候,我們只需要輸出 \(he_{n-1,m-1}*2+n+m\)

就是最終的答案。

\(code\):

#include<bits/stdc++.h>
using std::cout; using std::endl;
#define debug cout<<"debug"<<endl
//#define int long long
namespace xin_io
{
	#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1++
	#define scanf eat1 = scanf
	#define freopen eat2 = freopen
	int eat1; FILE *eat2; char buf[1<<20],*p1 = buf,*p2 = buf;
	inline void openfile() {freopen("t.txt","r",stdin);} inline void outfile() {freopen("o.txt","w",stdout);}
	template<class type>inline type get()
	{
		type s = 0,f = 1; register char ch = gc();
		while(!isdigit(ch)) {if(ch == '-') f = -1; ch = gc();}
		while(isdigit(ch))  {s = s * 10 + ch - '0'; ch = gc();}
		return s * f;
	}
}
using namespace xin_io; static const int maxn = 4e3+10,inf = 0x7f7f7f,mod = (1<<30);
#define try(i,a,b) for(register signed i=a;i<=b;++i)
#define throw(i,a,b) for(register signed i=a;i>=b;--i)
typedef long long ll;
namespace xin
{
	#define max(a,b) (a > b ? a : b)
	int he[maxn][maxn][2],f[maxn][maxn];
	int T,ans = 0;
	inline int gcd(int x,int y)
	{return !y ? x : gcd(y,x%y);}
	inline int gan(int n,int m,int i,int j)
	{
		if(gcd(i,j) == 1)
			return (n - i) * (m - j) - (max(n - (i << 1),0) * (max(m - (j << 1),0)));
		else return 0;
	}
	inline short main()
	{
	#ifndef ONLINE_JUDGE
		openfile();
	#endif
		T = get<signed>();
		try(i,1,4000)
			try(j,1,4000)
			{
				he[i][j][0] = (he[i-1][j][0] + he[i][j-1][0] - he[i-1][j-1][0] + (gcd(i,j) == 1));
				he[i][j][1] = (he[i-1][j][1] + he[i][j-1][1] - he[i-1][j-1][1] - he[i/2][j/2][0] + he[i][j][0]);
				he[i][j][0] &= (mod - 1); he[i][j][1] &= (mod - 1);
			}
		try(que,1,T)
		{
			register int n = get<signed>(),m = get<signed>();
			printf("%d\n",(n + m + 2 * he[n-1][m-1][1]) & (mod - 1));
		}
		return 0;
	}
}
signed main() {return xin::main();}

T2:

\(T2\) 到最後還是暴力收場了,用並查集優化也是我沒有想到的,思路還是要再寬一點。

我們對於權值進行排序,運用貪心的思想,然後從其中權值最大的開始,把連線他的並且權值比他大的邊進行合併就可以,之後開始計算這個聯通集合當中的最長路和最長路兩端的端點,為什麼要計算兩端的端點呢?我們就需要知道一個類似性質的東西。

對於合併兩個聯通集合,其新出現的最長路的端點一定會從兩個聯通集合原先的最長路的四個端點中選出。

知道這個性質,我們就可以輕鬆的算出來這個新的聯通集合的最長路了。

\(6\) 種情況討論。

就好比這兩個。

  1. 1 4
  2. 1 5
  3. 1 8
  4. 4 5
  5. 4 8
  6. 5 8
    分成這六種情況開始計算。之後每次合併更新答案。

\(code\):

#include<bits/stdc++.h>
using std::cout; using std::endl;
#define int long long
#define debug cout<<"debug"<<endl
namespace xin_io
{
	#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1++
	#define scanf eat1 = scanf
	#define freopen eat2 = freopen
	int eat1; FILE *eat2; char buf[1<<20],*p1 = buf,*p2 = buf;
	inline void openfile() {freopen("t.txt","r",stdin);} inline void outfile() {freopen("o.txt","w",stdout);}
	template<class type>inline type get()
	{
		type s = 0,f = 1; register char ch = gc();
		while(!isdigit(ch)) {if(ch == '-') f = -1; ch = gc();}
		while(isdigit(ch))  {s = s * 10 + ch - '0'; ch = gc();}
		return s * f;
	}
}
using namespace xin_io; static const int inf = 0x7f7f7f7f,mod = 998244353;
#define try(i,a,b) for(register signed i=a;i<=b;++i)
#define throw(i,a,b) for(register signed i=a;i>=b;--i)
typedef long long ll;
#define m(c,size) memset(c,0,size)
int n,T;
namespace xin
{
	const int maxn = 1e6+10;
	class xin_edge{public:int next,ver,w;}edge[maxn];
	class xin_data
	{
		public:
			int id,w;
			friend bool operator < (xin_data x,xin_data y)
			{return x.w > y.w;}
	}c[maxn];
	int head[maxn],zhi = 0;
	inline void add(int x,int y,int z) {edge[++zhi].ver = y; edge[zhi].w = z;edge[zhi].next = head[x]; head[x] = zhi;}	
/*	inline bool pan(int ci)
	{	
		double t = (double)clock() / (double)CLOCKS_PER_SEC;
		if(t > ci * tmax) return false;
		return true;
	}*/
	inline int random(int x) {return (ll) rand() * rand() % x;}
	int top[maxn],size[maxn],hson[maxn],d[maxn],fa[maxn],he[maxn];

	void dfs1(int x,int f)
	{
		d[x] = d[f] + 1; fa[x] = f; size[x] = 1;
		for(register int i=head[x];i;i=edge[i].next)
		{
			register int y = edge[i].ver,z = edge[i].w;
			if(y == f) continue;
			he[y] = he[x] + z;
			dfs1(y,x);
			size[x] += size[y];
			if(size[y] > size[hson[x]]) hson[x] = y;
		}
	}
	void dfs2(int x,int t)
	{
		top[x] = t;
		if(hson[x]) dfs2(hson[x],t);
		for(register int i=head[x];i;i=edge[i].next)
		{
			register int y = edge[i].ver;
			if(y == fa[x] or y == hson[x]) continue;
			dfs2(y,y);
		}
	}
	inline int lca(int x,int y)
	{
		while(top[x] != top[y])
		{
			if(d[top[x]] < d[top[y]]) std::swap(x,y);
			x = fa[top[x]];
		}
		if(d[x] > d[y]) std::swap(x,y);
		return x;
	}
//	void merge(int x,int y) {f[find(y)] = find(x);}
	inline int getdis(int x,int y)
	{
		int nc = lca(x,y);
		return he[x] + he[y] - 2 * he[nc];
	}
	int val[maxn];
	ll ans;
	class xin_bcj
	{
		public:
			int l,r,id,minn;
			ll dis;
			xin_bcj(){}	
			xin_bcj(int l,int r,int id,int minn):l(l),r(r),id(id),minn(minn){}
	}bcj[maxn];
	inline int find(int x){return x == bcj[x].id ? bcj[x].id : bcj[x].id = find(bcj[x].id);}
	inline void clear()
	{
		zhi = 0; 
		m(head,sizeof(int) * (n+1));
		try(i,1,n) 
		{	
			edge[i].next = edge[i].ver = edge[i].w = 0;
			bcj[i] = xin_bcj(0,0,0,0);
		}
		m(top,sizeof(int) * (n+1)); m(size,sizeof(int) * (n+1)); m(hson,sizeof(int) * (n+1));
		m(d,sizeof(int) * (n + 1)); m(fa,sizeof(int) * (n + 1));
	}
	inline void merge(int x,int y)
	{
		if(find(x) == find(y)) return ;
		register int fx = find(x),fy = find(y);
		bcj[fx].id = fy; bcj[fy].minn = std::min(bcj[fy].minn,bcj[fx].minn);
		int maxx = -inf,newl,newr;
		register int xl = bcj[fx].l,xr = bcj[fx].r,yl = bcj[fy].l,yr = bcj[fy].r,temp;
		if((temp = getdis(xl,yl)) > maxx) {maxx = temp;newl = xl; newr = yl;}
		if((temp = getdis(xl,yr)) > maxx) {maxx = temp;newl = xl; newr = yr;}
		if((temp = getdis(xr,yl)) > maxx) {maxx = temp;newl = xr; newr = yl;}
		if((temp = getdis(xr,yr)) > maxx) {maxx = temp;newl = xr; newr = yr;}
		if((temp = getdis(xl,xr)) > maxx) {maxx = temp;newl = xl; newr = xr;}
		if((temp = getdis(yl,yr)) > maxx) {maxx = temp;newl = yl; newr = yr;}
		bcj[fy].dis = maxx; bcj[fy].l = newl; bcj[fy].r = newr;
		ans = std::max(ans,1ll * bcj[fy].minn * bcj[fy].dis);
	}
	inline short main()
	{
//	#ifndef ONLINE_JUDGE
//		openfile();
//	#endif
//		srand((unsigned)(time(0)));
//		T = get<signed>();
//		tmax = 2.40 / (T * 1.0);
		try(que,1,T)
		{
			if(que xor 1) clear();
			if(que xor 1) n = get<signed>();
			try(i,1,n) c[i].w = get<signed>(),c[i].id = i,val[i] = c[i].w;
			try(i,1,n) bcj[i].id = bcj[i].l = bcj[i].r = i,bcj[i].minn = val[i];
			try(i,1,n-1)
			{
				register int x = get<signed>(),y = get<signed>(),z = get<signed>();
				add(x,y,z); add(y,x,z);
			}
			dfs1(1,0); dfs2(1,1);std::sort(c+1,c+n+1);
			ans = -inf;
			try(i,1,n)
			{
				register int x = c[i].id;
				for(register int i=head[x];i;i=edge[i].next)
				{
					register int y = edge[i].ver;
					if(val[y] < val[x]) continue;
					merge(x,y);
				}
			}
			cout<<ans<<endl;
		}
		return 0;
	}
}
signed main() 
{
#ifndef ONLINE_JUDGE
	openfile();
#endif
	T = get<signed>();	n = get<signed>();
	xin::main();
	return 0;
}

T3:

首先讀懂題意,然後發現顯然用線段樹維護。

然而並不是很好去維護,我們還是需要記錄很多變數分很多中情況討論。

首先提供 \(30pts\) 做法:

就是暴力列舉每一個剩下的位置。

然後去尋找那個能離某個花精最遠的位置。

然而也並不是很好寫。。。。

#include<bits/stdc++.h>
using std::cout; using std::endl;
#define debug cout<<"debug"<<endl
namespace xin_io
{
	#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1++
	#define scanf eat1 = scanf
	#define freopen eat2 = freopen
	int eat1; FILE *eat2; char buf[1<<20],*p1 = buf,*p2 = buf;
	inline void openfile() {freopen("t.txt","r",stdin);} inline void outfile() {freopen("o.txt","w",stdout);}
	template<class type>inline type get()
	{
		type s = 0,f = 1; register char ch = gc();
		while(!isdigit(ch)) {if(ch == '-') f = -1; ch = gc();}
		while(isdigit(ch))  {s = s * 10 + ch - '0'; ch = gc();}
		return s * f;
	}
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 0x7f7f7f,mod = 998244353;
#define try(i,a,b) for(register signed i=a;i<=b;++i)
#define throw(i,a,b) for(register signed i=a;i>=b;--i)
typedef long long ll;
namespace xin
{
	bool vis[maxn];
	int n,m;
	int head[maxn];
	class xin_data
	{
		public:
			int x,far;
			friend bool operator < (xin_data x,xin_data y)
			{return (x.far == y.far) ? x.x < y.x : x.far > y.far;}
			xin_data(){}
			xin_data(int x,int far):x(x),far(far){}
	};
	std::priority_queue<xin_data>q;
	xin_data que[maxn];int zhi = 0;
	inline int getmax(int pos)
	{
		int r = 0;
		throw(i,n,1) if(vis[i]) {r = i; break;}
		if(!r) {vis[1] = 1; head[pos] = 1; return 1;}
		int far = 0,maxv = -inf,maxp;
		try(i,1,n)
		{
			if(vis[i]) continue;
//			while(!q.empty()) q.pop();
			zhi = 0;
			try(j,0,n)
			{
				if(i + j <= n and vis[i + j]) {que[++zhi] = xin_data(i,j); break;}
				if(i - j >= 1 and vis[i - j]) {que[++zhi] = xin_data(i,j); break;}
//				std::sort(que+1,que+zhi+1);
			}
			int temp = que[zhi].x,away = que[zhi].far;
			if(away > maxv or (away == maxv and temp < maxp))
				maxv = away,maxp = temp;
		}
		vis[maxp] = 1; return head[pos] = maxp;
	}
	inline short main()
	{
	#ifndef ONLINE_JUDGE
		openfile();
	#endif
		n = get<signed>(); m = get<signed>();
		try(que,1,m)
		{
			register int op = get<signed>(),pos = get<signed>();
			if(op == 1)
				printf("%d\n",getmax(pos));
			else
				vis[head[pos]] = false;
		}
		return 0;
	}
}
signed main() {return xin::main();}

對於 \(%60\) 的資料:

題解對我發起了挑戰,所以我就搞出來了一個能拿到 \(60pts\) 的做法

所以以後這個題解該改一改了

\(set\) 維護之間距離,然後 \(iterator\) 遍歷取出元素就行了。

#include<bits/stdc++.h>
using std::cout; using std::endl;
#define debug cout<<"debug"<<endl
namespace xin_io
{
	#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1++
	#define scanf eat1 = scanf
	#define freopen eat2 = freopen
	int eat1; FILE *eat2; char buf[1<<20],*p1 = buf,*p2 = buf;
	inline void openfile() {freopen("t.txt","r",stdin);} inline void outfile() {freopen("o.txt","w",stdout);}
	template<class type>inline type get()
	{
		type s = 0,f = 1; register char ch = gc();
		while(!isdigit(ch)) {if(ch == '-') f = -1; ch = gc();}
		while(isdigit(ch))  {s = s * 10 + ch - '0'; ch = gc();}
		return s * f;
	}
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 0x7f7f7f,mod = 998244353;
#define try(i,a,b) for(register signed i=a;i<=b;++i)
#define throw(i,a,b) for(register signed i=a;i>=b;--i)
typedef long long ll;
namespace xin
{
	std::set<int>s;
	int n,m;
	bool vis[maxn];
	int head[maxn];
	inline int query(int bian)
	{
		if(!s.size()) {vis[1] = 1;s.insert(1); return head[bian] = 1;}
		if(s.size() == 1)
		{
			int pos = *s.begin();
			int r = n - pos,l = pos - 1;
			if(r > l) {s.insert(n); vis[n] = 1; return head[bian] = n;}
			else {s.insert(1); vis[1] = 1; return head[bian] = n;}
		}
		else
		{
			int l_pos = *s.begin(),r_pos = *s.end(),now,last = l_pos;
			int maxv = -inf,maxp;
			std::set<int>::iterator it;
			for(it = s.begin();it != s.end();++it)
			{
//				if(bian == 8) cout<<" *it =  "<<*it<<endl;
				if(*it == l_pos) continue;
				now = (*it - last - 2) / 2;
//				if(bian == 8) cout<<"*it = "<<*it<<" last = "<<last<<" now = "<<now<<endl;
				if(maxv < now and (*it - last - 2) >= 0) {maxv = now; maxp = now + last + 1;/*if(bian == 5) cout<<"maxp = "<<maxp<<endl;*/}
				last = *it;	
			}
//			if(bian == 8) cout<<"maxp = "<<maxp<<" maxv = "<<maxv<<" last = "<<last<<" l_pos = "<<l_pos<<endl;
			int l_max = l_pos - 2,r_max = n - last - 1;
//			if(bian == 8) cout<<"l_max = "<<l_max<<" r_max = "<<r_max<<endl;
			if(l_max >= maxv and l_max >= r_max) {s.insert(1); vis[1] = 1; return head[bian] = 1;}
			else
			{
				if(r_max > maxv) {s.insert(n); vis[n] = 1; return head[bian] = n;}
				else {s.insert(maxp); vis[maxp] = 1; return head[bian] = maxp;}
			}
		}
	}
	inline short main()
	{
	#ifndef ONLINE_JUDGE
		openfile();
	#endif
		n = get<signed>(); m = get<signed>();
		try(que,1,m)
		{
			register int op = get<signed>(),bian = get<signed>();
			if(op == 1)
				printf("%d\n",query(bian));
			else vis[bian] = false,s.erase(head[bian]);;
		}
		
		return 0;
	}
}
signed main() {return xin::main();}

然後就是正解,維護線段樹,每次的答案就是 \(t[1].ans\)

就這樣。

只不過要寫一堆東西,說也說不清,所以看程式碼就行了。。。。。

#include<bits/stdc++.h>
using std::cout; using std::endl;
#define debug cout<<"debug"<<endl
namespace xin_io
{
	#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1++
	#define scanf eat1 = scanf
	#define freopen eat2 = freopen
	int eat1; FILE *eat2; char buf[1<<20],*p1 = buf,*p2 = buf;
	inline void openfile() {freopen("t.txt","r",stdin);} inline void outfile() {freopen("o.txt","w",stdout);}
	template<class type>inline type get()
	{
		type s = 0,f = 1; register char ch = gc();
		while(!isdigit(ch)) {if(ch == '-') f = -1; ch = gc();}
		while(isdigit(ch))  {s = s * 10 + ch - '0'; ch = gc();}
		return s * f;
	}
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 0x7f7f7f,mod = 998244353;
#define try(i,a,b) for(register signed i=a;i<=b;++i)
#define throw(i,a,b) for(register signed i=a;i>=b;--i)
typedef long long ll;
namespace xin
{
	int n,m;
	class xin_segment	
	{
		private:
			#define ls(fa) (fa << 1)
			#define rs(fa) (fa << 1 | 1)
			inline void up(int fa,int l,int r)
			{
				t[fa].mid_mid_val = t[ls(fa)].mid_mid_val; t[fa].l_l_mid_val = t[ls(fa)].l_l_mid_val; t[fa].r_r_mid_val = t[ls(fa)].r_r_mid_val;
				if(((t[fa].mid_mid_val + 1) >> 1) < ((t[rs(fa)].l_mid_val + t[ls(fa)].r_mid_val + 1) >> 1))
					t[fa].mid_mid_val = t[rs(fa)].l_mid_val + t[ls(fa)].r_mid_val,t[fa].l_l_mid_val = t[ls(fa)].l_r_val,t[fa].r_r_mid_val = t[rs(fa)].r_l_val;
				if(((t[fa].mid_mid_val + 1) >> 1) < ((t[rs(fa)].mid_mid_val + 1) >> 1))
					t[fa].mid_mid_val = t[rs(fa)].mid_mid_val,t[fa].l_l_mid_val = t[rs(fa)].l_l_mid_val,t[fa].r_r_mid_val = t[rs(fa)].r_r_mid_val;
//				cout<<"t[rs(fa)].l_l_mid_val = "<<t[rs(fa)].l_l_mid_val<<endl;
				register int mid = l + r >> 1;
				t[fa].l_mid_val = t[ls(fa)].l_mid_val; t[fa].r_l_val = t[ls(fa)].r_l_val;
				if(t[fa].l_mid_val == mid + 1 - l) t[fa].l_mid_val += t[rs(fa)].l_mid_val,t[fa].r_l_val = t[rs(fa)].r_l_val;

				t[fa].r_mid_val = t[rs(fa)].r_mid_val; t[fa].l_r_val = t[rs(fa)].l_r_val;
				if(t[fa].r_mid_val == r - mid) t[fa].r_mid_val += t[ls(fa)].r_mid_val,t[fa].l_r_val = t[ls(fa)].l_r_val;
			}
		public:
			class xin_tree{public:int mid_mid_val,l_l_mid_val,r_r_mid_val,l_mid_val,r_mid_val,r_l_val,l_r_val;}t[maxn];	
			inline void build(int fa,int l,int r)
			{
				t[fa].l_mid_val = t[fa].r_mid_val = t[fa].mid_mid_val = r - l + 1;
				t[fa].l_l_mid_val = t[fa].l_r_val = l; t[fa].r_l_val = t[fa].r_r_mid_val = r;
				if(l == r) return ;
				register int mid = l + r >> 1;
				build(ls(fa),l,mid); build(rs(fa),mid+1,r);
				up(fa,l,r);
			}
			inline void modify(int fa,int l,int r,int pos,int val)
			{
				if(pos > r or pos < l )return;
				if(l == r)
				{
					if(val == 2) t[fa].mid_mid_val = t[fa].l_mid_val = t[fa].r_mid_val = 1,t[fa].l_l_mid_val = t[fa].r_r_mid_val = t[fa].l_r_val = t[fa].r_l_val = pos;
					else t[fa].mid_mid_val = t[fa].l_mid_val = t[fa].r_mid_val = 0,t[fa].l_l_mid_val = t[fa].l_r_val = pos + 1,t[fa].r_r_mid_val = t[fa].r_l_val = pos - 1;
					return ;
				}
				register int mid = l + r>> 1;
				modify(ls(fa),l,mid,pos,val); modify(rs(fa),mid+1,r,pos,val);
				up(fa,l,r);
			}
	}t;
	int head[maxn];
	inline short main()
	{
	#ifndef ONLINE_JUDGE
		openfile();
	#endif
		n = get<signed>(); m = get<signed>();
		t.build(1,1,n);
		try(i,1,m)
		{
			register int op = get<signed>(),bian = get<signed>();
			if(op == 2)
				t.modify(1,1,n,head[bian],2);
			else
			{
				int pos = (t.t[1].r_r_mid_val + t.t[1].l_l_mid_val) >> 1;
				if(t.t[1].l_l_mid_val == 1 or t.t[1].l_mid_val >= (t.t[1].mid_mid_val + 1) >> 1) pos = 1;
				else if(t.t[1].r_r_mid_val == n or t.t[1].r_mid_val > (t.t[1].mid_mid_val + 1) >> 1) pos = n;
				printf("%d\n",pos);
//				cout<<"pos = "<<pos<<endl;
				t.modify(1,1,n,pos,1);
				head[bian] = pos;
			}
		}
		return 0;
	}
}

signed main() {return xin::main();}