noip51

T1

一开始想的dp,发现自己不会,看数据,想着应该是个 \(O(n)\) 的做法,然而自己还是不会,直接走了。

正解:

一个简单(?)的递推。

首先对于一个操作区间 \([l,r]\) ,如果这一段颜色相同,那么就没有必要进行施法,所以每个位置之可能与相邻的最近两个颜色相同的位置进行操作。

\(f_{i}\) 表示之考虑前 \(i\) 个位置的方案数。

考虑新加入一个位置 \(i\) 时,设其位置上的颜色上一次出现的位置为 \(j\) ,若这样的 \(j\) 不存在,则无法进行操作,或者不操作,直接继承过来,即 \(f_{i}=f_{i-1}\) ,如果存在的话,还要加上 \([j,i]\) 这一段被染成同一颜色的贡献,注意一下当 \(j=i-1\) 时,这样是不会产生贡献的。

所以总的就有 \(f_{i}=f_{i-1}+[i-j>1]·f_{j}\)

T2

一开始看是概率期望就先放了,最后一个小时回来,发现并没自己想的那么难。

考场想法:

枚举赢了 \(i\) 场,输了 \(j\) 场,那么就有一个很显然的式子出来:

\[ans=\sum_{i=1}^{n} \tbinom{n}{i} \sum_{j=0}^{\min(i-1,n-i)} \binom{n-i}{j} \times (\frac{1}{p+2})^{i+j}\times(\frac{p}{p+2})^{n-i-j}\times (n-i-j+1) \]

直接写是 \(n^{2}\) 的。 然后试图拆开化一波式子,发现因为枚举输赢的原因,没法化简,或者我不会。然后这题就又被我弃了。

正解:

其实换一个方向考虑就会很简单。

发现对答案有直接贡献的为平局场次,那就去枚举平局场次 \(k\) ,那么输赢场次和起来就为 \(n-k\) ,按照题意,有贡献的前提条件是赢的场次严格大于输的场次,所以赢场 \(i\in[\lfloor\frac{n-k}{2}\rfloor+1,n-k]\) ,这样的话,就又有一个很显然的式子:

\[ans=\sum_{k=0}^{n-1} \tbinom{n}{k} \times (\frac{p}{p+2})^{k} \times(k+1) \times (\frac{1}{p+2})^{n-k} \sum_{i=\lfloor\frac{n-k}{2}\rfloor+1}^{n-k} \tbinom{n-k}{i} \]

所以直接算也是 \(n^2\) 的,但现在的式子就可以很简单的化简了。

\(\sum_{m=0}^{n}\tbinom{n}{m}=2^{n}\)\(\tbinom{n}{m}=\tbinom{n}{n-m}\) 可知:

\[ \sum_{i=\lfloor\frac{n-k}{2}\rfloor+1}^{n-k} \tbinom{n-k}{i}=\frac{2^{n-k}-[(n-k)\;is\;even]\tbinom{n-k}{\frac{n-k}{2}}}{2} \]

如何出来的右边式子?

分奇偶讨论一下,当 \(n-k\) 为 奇数时,左边的求和就一共有偶数项,算上了0,举个例子,\(n-k=3\) 时:

\[\tbinom{3}{0}+\tbinom{3}{1}+\tbinom{3}{2}+\tbinom{3}{3} \]

前两项对应等于后两项,而只有后两项对应的意义能产生贡献,所以我只需要后一半,那直接拿 \(2^{3}\) 除以个2即可,同样,类比到其他奇数情况就直接除以2。

\(n-k\) 为偶数时,再举个例子,\(n-k=2\) 时:

\[\tbinom{2}{0}+\tbinom{2}{1}+tbinom{2}{2} \]

跟奇数情况同样的考虑方法,发现中间项,即当输的场数等于赢的场数时,不合法,需要减掉,剩下的就跟奇数情况一样了。

一种思路做不了,或者无法优化下去,可以去换一种思路,不要在一棵树上吊死。

T3

考场只会打暴力。

正解:

考虑将权值在 \([l,r]\) 之间的数所在的格子都染成黑色,其他格子都染成白色。

将原矩阵往外扩一圈,这样就会有 \((n+1)\times(m+1)\)\(2\times2\) 的小正方形。

那么染色后,至少有四个小正方形有一个格子被染成了黑色,同时要让染色后的格子形成一个合法的矩形,还要满足没有一个小正方形被染了3个黑色格子。

将权值排序,从小到大枚举 \(r\),对于每个 \(l<r\) ,设 \(f_{l}\) 表示在染黑权值 \([l,r]\) 后,被染了一个格子的小正方形和被染了三个格子的小正方形的个数,那么如果当前这段区间合法,那么必须满足 \(f_{l}=4\)

所以对于当前枚举到的 \(r\) ,只需维护\(l\in[1,r-1]\)\(f_{l}\) 的最小值,能取到最小值的 \(l\) 个数和对应的 \(l\) 之和即可。

考虑将 \(r\) 增加1,即枚举下一个 \(r\) ,只会影响到其周围的四个小正方形,如图所示:

没画图工具,咕了

所以只需要在线段树上修改即可。

Code
#include<vector>
#include<cstdio>
#include<algorithm>
#define MAX 200003
#define re register
#define INF 1145141919
//#define int long long
const int mod = 998244353;
using std::sort;
using std::vector;
namespace some
{
	struct stream
	{
		template<typename type>inline stream &operator >>(type &s)
		{
			int w=1; s=0; char ch=getchar();
			while(ch<'0'||ch>'9'){ if(ch=='-')w=-1; ch=getchar(); }
			while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); }
			return s*=w,*this;
		}
	}cin;
	auto debug = []() -> void { printf("fuck\n"); };
	auto min = [](int a,int b) ->int { return a<b?a:b; };
	auto fd = [](int a,int b) ->int { return b-mod+a>=0?b-mod+a:a+b; };
}using namespace some;
namespace OMA
{
	int n,m,ans,tot;C
	struct TREE
	{
		int nim;
		int cnt;
		int lazy;
		long long sum;
	}st[MAX<<2];
	#define ls(p) p<<1
	#define rs(p) p<<1|1
	#define mid (l+r>>1)
	auto Push_up = [](int p) -> void
	{
		st[p].cnt = st[p].sum = 0;
		st[p].nim = min(st[ls(p)].nim,st[rs(p)].nim);
		if(st[p].nim==st[ls(p)].nim)
		{ st[p].cnt += st[ls(p)].cnt,st[p].sum += st[ls(p)].sum; }
		if(st[p].nim==st[rs(p)].nim)
		{ st[p].cnt += st[rs(p)].cnt,st[p].sum += st[rs(p)].sum; }
	};
	auto Push_down = [](int p) -> void
	{C
		if(!st[p].lazy)
		{ return ; }
		st[ls(p)].nim += st[p].lazy;
		st[ls(p)].lazy += st[p].lazy;
		st[rs(p)].nim += st[p].lazy;
		st[rs(p)].lazy += st[p].lazy;
		st[p].lazy = 0;
	};
	inline void build(int p,int l,int r)
	{
		if(l==r)
		{ st[p].nim = INF,st[p].cnt = 1,st[p].sum = l; return ; }
		build(ls(p),l,mid),build(rs(p),mid+1,r);
		Push_up(p);
	}
	inline void modify(int p,int l,int r,int pos)
	{
		if(l==r)
		{ st[p].nim = 0,st[p].cnt = 1,st[p].sum = l; return ; }
		Push_down(p);
		if(pos<=mid)
		{ modify(ls(p),l,mid,pos); }
		else
		{ modify(rs(p),mid+1,r,pos); }
		Push_up(p);
	}
	inline void update(int p,int l,int r,int lp,int rp,int val)
	{
		if(lp<=l&&r<=rp)
		{ st[p].nim += val,st[p].lazy += val; return ; }
		Push_down(p);
		if(lp<=mid)
		{ update(ls(p),l,mid,lp,rp,val); }
		if(rp>mid)
		{ update(rs(p),mid+1,r,lp,rp,val); }
		Push_up(p);
	}
	vector<int>a[MAX];
	struct node
	{
		int x,y,val;
		inline friend bool operator <(const node &a,const node &b)
		{ return a.val<b.val; }
	}my[MAX];
	int w[5];
	auto change = [](int r,int cnt = 3) -> void
	{
		//debug();
		sort(w+1,w+1+cnt);
		while(w[cnt]>r)
		{ cnt--; }
		//printf("r=%d\n",r);
		//for(re int i=1; i<=cnt; i++)
		//{ printf("%d ",w[i]); }
		//printf("\n");
		w[cnt+1] = r;
		//printf("begin\n");
		for(re int i=cnt; ~i; i--)
		{
			if(cnt-i&1)
			{ /*printf("1\n");*/ update(1,1,tot,w[i]+1,w[i+1],-1); }
			else
			{ /*printf("2\n");*/ update(1,1,tot,w[i]+1,w[i+1],1); }
		}
		//printf("end\n\n");
	};
	auto main = []() -> signed
	{
		freopen("pig.in","r",stdin);
		freopen("pig.out","w",stdout);
		cin >> n >> m;
		for(re int i=1,val; i<=n; i++)
		{
			a[i].push_back(INF);
			for(re int j=1; j<=m; j++)
			{ a[i].push_back((cin >> val,val)),my[++tot] = (node){i,j,val}; }
			a[i].push_back(INF);
		}
		for(re int i=0; i<=m+1; i++)
		{ a[0].push_back(INF),a[n+1].push_back(INF); }
		build(1,1,tot); sort(my+1,my+1+tot);
		//printf("tot=%d\n",tot); printf("QAQ\n");
		for(re int i=1,x,y,r; i<=tot; i++)
		{
			x = my[i].x,y = my[i].y,r = my[i].val; modify(1,1,tot,r);
			//debug(); printf("i=%d\n",i);
			//printf("x=%d y=%d r=%d\n",x,y,r);
			w[1] = a[x][y-1],w[2] = a[x-1][y-1],w[3] = a[x-1][y]; change(r);
			w[1] = a[x][y-1],w[2] = a[x+1][y-1],w[3] = a[x+1][y]; change(r);
			w[1] = a[x][y+1],w[2] = a[x-1][y+1],w[3] = a[x-1][y]; change(r);
			w[1] = a[x][y+1],w[2] = a[x+1][y+1],w[3] = a[x+1][y]; change(r);
			//printf("t=%d min=%d cnt=%d sum=%d\n",i,st[1].nim,st[1].cnt,st[1].sum);
			if(st[1].nim==4)
			{ ans = fd(ans,fd((1ll*st[1].cnt*r-st[1].sum)%mod,st[1].cnt)); /*debug();*/ }
		}
		printf("%d\n",ans);
		return 0;
	};
}
signed main()
{ return OMA::main(); }

T4

状压20pts,正解不会咕咕咕。

posted @ 2021-09-15 11:10  -OMA-  阅读(82)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end