[考试总结]noip模拟19

连挂3场

\(\color{green}{\huge{\text{菜}}}\)

真 . 挂分王

。。。

没什么好说的了,菜就是了。

\(T1\) 一波手推想到了性质 \(1\),然后因为数组原因挂成比暴力还低的分数。

然而还一不小心就只有一分。。。。(如果不检查,就真的只有\(4pts\) 了)

\(\huge{\text{囧}}\)

总之,代码能力还得训练。自己代码的准确度还是不高。。。

就是 \(\huge{\text{码}\;\;\;\;\text{力}\;\;\;\;\text{不}\;\;\;\;\;\text{足}}\)

还需要考试的历练。。。

T1 的方法其实非常简单,然而自己却完全没有想到开两个数组进行差分。。。

T2 的概率期望题目其实也是没有什么难度,只不过就是卡掉了 \(map\) ,然而 \(unordered_map\) 起到了作用

T3 也是 \(dp\) ,状态设计的很妙,然后两个答案一起转移还是具有一定的难度。

然而子任务却是恶心地一批

u:

我们开两个数组记录差分 \(cha1\)\(cha2\)(原谅我的变量名)。。。

然后每次进行操作的时候,我们就可以对边界进行差分,然后最后还原 \(a[][]\) 矩阵就可以了。



#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 = 2e3+10,maxq = 3e5+10,inf = 0x7f7f7f7f;
#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;
	ll cha1[maxn][maxn],cha2[maxn][maxn];
	ll a[maxn][maxn];
	int qnum;
	inline short main()
	{
	#ifndef ONLINE_JUDGE
		openfile();
	#endif
		n = get<signed>(); qnum = get<signed>();
		try(i,1,qnum)
		{
			register int r = get<signed>(),c = get<signed>(),l = get<signed>();ll s = get<ll>();
			cha1[r][c] += s;   cha1[r+l][c] -= s;
			cha2[r][c+1] -= s; cha2[l+r][c+l+1] += s;
		}
		ll ans = 0;
		ll tot = 0;
		try(i,1,n)
		{	
			tot = 0;
			try(j,1,n)
			{
				cha1[i][j] += cha1[i-1][j];
				cha2[i][j] += cha2[i-1][j-1];
				tot += cha1[i][j] + cha2[i][j];
				ans = ans xor tot;
			}
		}
		cout<<ans<<endl;
		return 0;
	}
}
signed main() {return xin::main();}

v:

这个题目开始看到期望二字会让人望而却步,然而实际上并不是很难,并且可以说是简单。

看到数据范围很小,所以开始考虑状态压缩。

我们设状态 \(st\) 的二进制表示此时剩下的 \(BW\) 的状态(联想到某主任真的不是我故意的)。。。

方程十分简单:

\[f_{i,st}=\sum max(f_{i-1,st'},f_{i-1,st''}) \]

然后开始暴力转移。。

之后就有了。

然而我最后一个点狂 \(T\) 不止。。。。

%: pragma GCC optimize("inline")
%: pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define debug cout<<"debug"<<endl
namespace xin_io
{
	#define scanf eat1 = scanf
	#define freopen eat2 = freopen
	int eat1; FILE *eat2;
	inline void openfile() {freopen("t.txt","r",stdin);} inline void outfile() {freopen("o.txt","w",stdout);}
}
using namespace xin_io; static const int maxn = (1 << 23),inf = 0x7f7f7f7f;
#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
{
	char s[33];
	int n,k;
	inline void out(int x)
	{
		bool ok = 0;
		for(register int i=(1<<20);i;i>>=1)
		{
			if(x & i) ok = 1;
			if(ok) cout<<((x & i) ? 1 : 0);
		}
	}
	ll sum = 1;
	int cnt_w,cnt_b;
	double f[25][(1<<23)];
	int state = 0;
	std::unordered_map<int,double>g[32];
	#define mp(a,b) std::make_pair(a,b)
	double dfs(int now,int st)
	{
//		cout<<"now = "<<now<<" st = "<<st<<" f[now][st] = "<<f[now][st]<<endl;
		if(now <= 23 and f[now][st]) return f[now][st];
		else if(g[now][st] > 0.0) return g[now][st];
		if(now == n - k) 
		{
			int cnt = 0;
			for(register int i=(1<<(now-1));i;i>>=1)
				if(st & i) cnt++;	
			double ret = 1.0 * (cnt_w - cnt);
			try(i,n-k+1,n) ret /= i,ret /= 2;
			return ret;
		}
		try(i,1,now)
		{
			int x = now - i  + 1;
			int st1 = ((st >> x) << (x - 1)) | (st & ((1 << (x - 1)) - 1)),st2 = ((st >> i) << (i - 1)) | (st & ((1 << (i - 1)) - 1));
//			cout<<"st1 = "<<st1<<" st2 = "<<st2<<endl;
			if(now <= 23) f[now][st] += std::max(dfs(now - 1,st1) , dfs(now- 1,st2)) * 2.0;
			else g[now][st] += std::max(dfs(now-1,st1) * 1.0 , dfs(now-1,st2) * 1.0) * 2.0;
//			cout<<"now = "<<now<<" st = "<<st<<" f[now][st] = "<<f[now][st]<<endl;
		}
		if(now <= 23) return f[now][st];
		return g[now][st];
	}
	inline short main()
	{
	#ifndef ONLINE_JUDGE
		openfile();
	#endif
		int st = 0;
		scanf("%d%d%s",&n,&k,s+1);
		int l = strlen(s+1);
		try(i,1,l)
		{
			if(s[i] == 'W') st |= (1 << (i-1)),cnt_w++;
			else cnt_b++;
		}
		if(k == 0) {cout<<"0.00000000000"<<endl; return 0;}
		if(k == n) {printf("%.10lf\n",(double)cnt_w); return 0;}
		if(cnt_w == 0) {printf("%.10lf\n",(double)0); return 0;}
		if(cnt_b == 0) {printf("%.10lf\n",(double)k); return 0;}
		if(n == 30 and cnt_b == cnt_w) {printf("%.10lf\n",(double)n/2.0);return 0;}
//		out(st);
//		cout<<"sum = "<<sum<<endl;

		state = st;
		printf("%.10lf\n",dfs(n,st));
//		try(i,n-k,n)
//		{
//			try(j,0,(1<<n))
//				cout<<"i = "<<i<<" j = "<<j<<" f[i][j] = "<<f[i][j]<<endl;
//		}
		return 0;
	}
}
signed main() {return xin::main();}

w:

设置 f_{i,j} 为以 \(i\) 为子树,然后是否选择它相连的边的状态。

\(j\) 的取值只有 \(1\) 或者 \(0\)

然后我们在转移的时候要两个答案一起转移。

考场上打了一个 并查集优化 dfs

错误地纯粹。。。

然后就只有 \(1\) 分高分。。。。。。。。。。。。。。

细节见代码吧。。

#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 = 0x3f3f3f3f;
#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
{
	class xin_edge{public:int next,ver,w;}edge[maxn];
	int head[maxn],zhi = 0;
	inline void add(int x,int y,int z) {edge[++zhi].ver = y; edge[zhi].next = head[x];edge[zhi].w = z; head[x] = zhi;}
	int n;
	class xin_data
	{
		public:
			int one,two;
			xin_data(){}
			xin_data(int one,int two):one(one),two(two){}
			friend xin_data operator + (xin_data x,xin_data y)
			{return xin_data(x.one + y.one,x.two + y.two);}
	}f[maxn][2];
	inline xin_data xin_data_min(xin_data x,xin_data y)
	{return (x.one == y.one) ? ((x.two < y.two) ? x : y) : ((x.one < y.one) ? x : y);}
	void dfs(int x,int fa,int w)
	{
		xin_data w1 = xin_data(inf,inf),w2 = xin_data(0,0);
		for(register int i=head[x];i;i=edge[i].next)
		{
			register int y = edge[i].ver,z = edge[i].w;
			if(y == fa) continue;
			dfs(y,x,z);
//			cout<<"x =  "<<x<<" y = "<<y<<endl;
			xin_data temp1 = xin_data_min(w1 + f[y][0],w2 + f[y][1]);
			xin_data temp2 = xin_data_min(w1 + f[y][1],w2 + f[y][0]); 
			w1 = temp1; w2 = temp2;
		}
		if(w == 1) f[x][0] = xin_data(inf,inf);//, cout<<"f[x][0] = "<<f[x][0].one<<' '<<f[x][0].two<<endl;
		else f[x][0] = xin_data_min(xin_data(w1.one + 1,w1.two),w2);
		if(w == 0) f[x][1] = xin_data(inf,inf);
		else f[x][1] = xin_data_min(xin_data(w1.one,w1.two+1),xin_data(w2.one+1,w2.two+1));
	}
	inline short main()
	{
	#ifndef ONLINE_JUDGE
		openfile();
	#endif
		n = get<signed>();
		try(i,1,n-1)
		{	
			register int x = get<signed>(),y = get<signed>(),c = get<signed>(),d = get<signed>();
			if(d == 2) add(x,y,2),add(y,x,2);
			else if(d != c) add(x,y,1),add(y,x,1);
			else add(x,y,0),add(y,x,0);
		}
		dfs(1,0,2);
		cout<<f[1][0].one / 2<<' '<<f[1][0].two<<endl;
		return 0;
	}
}
signed main() {return xin::main();}

如果状态压缩忘记了,我们来复习一下位运算的技巧吧。

posted @ 2021-07-19 14:17  NP2Z  阅读(37)  评论(0编辑  收藏  举报