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

[考試總結]noip模擬33

連炸兩場。。。

傷心。。。

第一個題目首先因為有期望坐鎮,然後跳過。。。

然後第二個題目發現題目挺繞的,然後轉化了一句話題意,然後。。。。。

\(\huge{\text{轉化錯了!!!!}}\)

然而。。。

\(\huge{\text{樣例過了!!!}}\)

什麼玩意!!!!!

然後就有 \(9pts\) 。。。

然後 \(T3\) 打了一個自己都覺得假的最大生成樹。

然後完全圖還沒有判斷正確,導致。。。。

只有 \(10pts\)

如果再這樣就真的要被翻了。。。。

Hunter

又是一個結論題。

其實這個看到題解之後完全不用懊悔

這個是真的不太好推出來。

雖然思路很簡單。

答案就是:

\[ans = \sum_{i=2}^{n}\frac{w_i}{w_1 + w_i} + 1 \]

然後就三行程式碼。。。。

#include<bits/stdc++.h>
typedef long long ll;const ll mod = 998244353; ll n,w[1000001],ans = 1;inline ll ksm(ll x,ll y) {register ll ret = 1; while(y) {if(y & 1) ret = ret * x % mod;x = x * x % mod; y >>= 1;} return ret;}
signed main() {std::cin >> n >> w[1]; for(ll i=2;i<=n;++i) std::cin >> w[i],(ans += w[i] * ksm(w[1] + w[i],mod-2) % mod) %= mod; std::cout<<ans;}

真不騙你,就三行。

Defence

這個題目的意思並不是要讓你求 \(0\) 的個數!!!!

而是求最長的連續 \(0\) 的個數。。。。

然後顯然發現可以線段樹合併。。。。

跟板子一樣。。。。

水得一批。。。。



#include<bits/stdc++.h>
using std::cout; using std::endl;
#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)
#define asm(i,x) for(register signed i=head[x];i;i=edge[i].next)
namespace xin_io
{
	#define debug cout<<"debug"<<endl
	#define enum(x) cout<<#x" = "<<x<<endl;
	#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1++
	char buf[1<<20],*p1 = buf,*p2 = buf; int ak; typedef long long ll; typedef unsigned long long ull;
	class xin_stream{public:template<typename type>inline xin_stream &operator >> (type &x)
	{
		register type s = 0; register int f = 1; register char ch = gc();
		while(!isdigit(ch)) {if(ch == '-') f = -1; ch = gc();}
		while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch  xor 48),ch = gc(); return x = s * f,*this;
	}}io;
}
using namespace xin_io; static const int maxn = 1e5+10,inf = 1e9+7,mod = 998244353; const ll llinf = 1e18+7;
namespace xin
{
	class xin_edge{public:int next,ver;}edge[maxn];
	int head[maxn],zhi = 0;
	inline void add(int x,int y) {edge[++zhi].ver = y; edge[zhi].next = head[x]; head[x] = zhi;}
	int root[maxn],tot;
	class xin_segment
	{
		private:
			#define ls(fa) (t[fa].lson)
			#define rs(fa) (t[fa].rson)
			inline void up(int fa)
			{
				t[fa].size = t[ls(fa)].size + t[rs(fa)].size;
				t[fa].s = std::max(t[ls(fa)].s , t[rs(fa)].s);
				if(t[rs(fa)].lpos and t[ls(fa)].rpos) t[fa].s = std::max(t[fa].s,t[rs(fa)].lpos - t[ls(fa)].rpos - 1);
				if(!t[rs(fa)].rpos) t[fa].rpos = t[ls(fa)].rpos; else t[fa].rpos = t[rs(fa)].rpos;
				if(!t[ls(fa)].lpos) t[fa].lpos = t[rs(fa)].lpos; else t[fa].lpos = t[ls(fa)].lpos;
			}
		public:
			class xin_tree{public:int s,lson,rson,lpos,rpos,size;}t[maxn * 32];
			void insert(int &fa,int l,int r,int pos)
			{
				if(!fa) fa = ++tot;
				if(l == r) {t[fa].lpos = t[fa].rpos = l; t[fa].size = 1; return ;}
				register int mid = l + r >> 1;
				if(pos <= mid) insert(ls(fa),l,mid,pos); else insert(rs(fa),mid+1,r,pos);
				up(fa);
			}
			int merge(int x,int y,int l,int r)
			{
				if(!x or !y) return x | y;
				if(l == r) return x;
				register int mid = l + r >> 1;
				ls(x) = merge(ls(x),ls(y),l,mid); rs(x) = merge(rs(x),rs(y),mid+1,r);
				up(x);
				return x;
			}
	}t;
	int n,m,qnum;
	int ans[maxn];
	void dfs(int x)
	{
		asm(i,x)
		{
			register int y = edge[i].ver;
			dfs(y);
			root[x] = t.merge(root[x],root[y],1,m);
		}
		if(!t.t[root[x]].size) ans[x] = -1;
		else ans[x] = std::max(t.t[root[x]].s,t.t[root[x]].lpos - 1 + m - t.t[root[x]].rpos);
	}
	inline short main()
	{
		io >> n >> m >> qnum;
		try(i,1,n-1)
		{
			register int x,y; io >> x >> y;
			add(x,y);
		}
		try(i,1,qnum)
		{
			register int x,y; io >> x >> y;
			t.insert(root[x],1,m,y);
		}
		dfs(1);
		try(i,1,n) printf("%d\n",ans[i]);
		return 0;
	}
}
signed main() {return xin::main();}

Connect

這個題目給人的第一直覺就是求一個最大生成樹,然後用總價減去

然後是假的,並且你可以過樣例。

然後 \(10pts\) 收場。。。。

我們可以考慮狀壓,因為發現這個 \(n\) 的範圍很小很小。

然後列舉補集的子集,很好轉移。。



%: pragma GCC optimize("O3","Ofast","inline")
#include<bits/stdc++.h>
using std::cout; using std::endl;
#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)
#define asm(i,x) for(register signed i=head[x];i;i=edge[i].next)
namespace xin_io
{
	#define debug cout<<"debug"<<endl
	#define enum(x) cout<<#x" = "<<x<<endl;
	#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1++
	char buf[1<<20],*p1 = buf,*p2 = buf; int ak; typedef long long ll; typedef unsigned long long ull;
	class xin_stream{public:template<typename type>inline xin_stream &operator >> (type &x)
	{
		register type s = 0; register int f = 1; register char ch = gc();
		while(!isdigit(ch)) {if(ch == '-') f = -1; ch = gc();}
		while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch  xor 48),ch = gc(); return x = s * f,*this;
	}}io;
}
using namespace xin_io; static const int maxn = 15,inf = 1e9+7,mod = 998244353; const ll llinf = 1e18+7;
namespace xin
{
	int sum[1<<maxn],dis[maxn][maxn];
	int n,m;
	int f[1<<maxn][maxn];
	inline short main()
	{
		io >> n >> m;
		try(i,1,m)
		{
			register int x,y,z; io >> x >> y >> z;
			dis[x-1][y-1] = dis[y-1][x-1] = z;
		}
		try(i,1,(1 << n) - 1)try(j,0,n-1)try(k,j+1,n-1)
			if(((i >> j) & 1) and ((i >> k) & 1))
				sum[i] += dis[j][k];
		memset(f,-0x3f,sizeof (f));
//		try(i,0,(1<<maxn)-1) try(j,0,maxn-1) f[i][j] = -inf;
		f[1][0] = 0;
		try(i,1,(1 << n) - 1)
			try(j,0,n - 1)
			{
				if(f[i][j] == -1044266559) continue;
				try(k,0,n - 1)if(dis[j][k] and !((1 << k) & i)) f[i | (1 << k)][k] = std::max(f[i | (1 << k)][k],f[i][j] + dis[j][k]);
				register int jihe = (i xor ((1 << n) - 1));
				for(register int k=jihe;k;k=(k-1)&jihe) f[i|k][j] = std::max(f[i|k][j],f[i][j] + sum[k|(1<<j)]);
			}
		printf("%d\n",sum[(1<<n)-1] - f[(1 << n) - 1][n-1]);
		return 0;
	}
}
signed main() {return xin::main();}