Loading

noip模拟39

A. 打地鼠

A_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS
{
	#define ll long long int
	#define re register ll 
	#define lf double
	#define lb lower_bound 
	#define ub upper_bound 
	#define mp make_pair
	#define File(x,y) freopen(#x,"r",stdin),freopen(#y,"w",stdout)
	#define Fill(x,y) memset(x,y,sizeof x);
	#define Copy(x,y) memcpy(x,y,sizeof x);
	inline ll read()
	{
		ll ss=0; bool cit=1; char ch;
		while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
		while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
		return cit?ss:-ss;
	}
} using namespace BSS;

const ll N=2051;
ll m,n,s,ans;
ll pre[N][N];
char ch[N];
signed main(){
	n=read(); s=read();
	for(re i=1;i<=n;i++){
		scanf("%s",ch+1);
		for(re j=1;j<=n;j++)
			pre[i][j]=pre[i-1][j]+pre[i][j-1]-pre[i-1][j-1]+ch[j]-'0';
	}
	ll temp;
	for(re i=s;i<=n;i++){
		for(re j=s;j<=n;j++){
			temp=pre[i][j]-pre[i-s][j]-pre[i][j-s]+pre[i-s][j-s];
			ans=max(ans,temp);
		}
	}
	printf("%lld",ans);
	return 0;
}

B. 竞赛图

一个我又没有想到也没有接触过的性质:
将每个点自己都看成一个强连通分量,
那么任意一个非强联通分量,都可以看成由一个强连通分量+强连通分量构成的.
然后可以明显地注意到题中给的一个关键性质:
任意两个点之间均有且只有一条有向边.
于是利用这两个性质用已有的强联通分量更新其它的非强联通分量即可.

B_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS
{
	#define ll int
	#define re register ll 
	#define lf double
	#define lbt(x) (x&(-x))
	#define lb lower_bound 
	#define ub upper_bound 
	#define mp make_pair
	#define File(x,y) freopen(#x,"r",stdin),freopen(#y,"w",stdout)
	#define Fill(x,y) memset(x,y,sizeof x);
	#define Copy(x,y) memcpy(y,x,sizeof x);
	inline ll read()
	{
		ll ss=0; bool cit=1; char ch;
		while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
		while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
		return cit?ss:-ss;
	}
} using namespace BSS;

const ll N=1<<25;
ll m,n,Ts,ans;
ll e[N],q[N];
inline void Pre(){
	fill(q,q+(1<<n),1),fill(e,e+(1<<n),0);
	ans=0; e[0]=(1<<n)-1;
}
inline void Work(){
	n=read(); Pre();
	for(re i=1;i<=n;++i)
		for(re j=1;j<=n;++j)
			e[1<<(i-1)]|=((1<<(j-1))*read());
	for(re i=1;i<=(1<<n)-1;++i) e[i]=e[i^lbt(i)]&e[lbt(i)];
	for(re i=1;i<=(1<<n)-1;++i)
		if(q[i]) for(re s=e[i];s;(--s)&=e[i]) q[s|i]=0;
	for(re i=0;i<=(1<<n)-1;++i) ans+=q[i];
	printf("%d\n",ans); return ;
}
signed main(){
	Ts=read();
	while(Ts--) Work();
	return 0;
}

C. 糖果

双维转移..第一次见到..
又是一个统计方案数,果断想到\(dp\)..
然后人生再一次定格.

\(fa_{i,j,k}\)\(fb_{i,j,k}\)表示\(A\)在选择第\(i\)个数、\(B\)在选择第\(j\)个数,\(C\)剩下\(k\)个备选位置时的方案数.
然后我们把\(A\)\(i,j\)的状态转移给\(B\),再把\(B\)\(i,j\)时的状态转移给\(A\)\(i+1,j+1\)
..
最后给答案分别乘上\(A_{3*i-1}^2\).
\(2\)是因为我们发现\(A\)\(B\)所选过的值在\(C\)中排列就可以了,因为这些值不是留给\(C\)的,但之所以\(3*i-1\)是因为当前\(C\)的值已经确定了位置.
关于如何想到这一类\(dp\),大概就是这一类两个互相影响的序列但是最终的目标是同一个结果的时候可以稍微考虑一下吧..

B_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS
{
	#define ll long long int
	#define re register int
	#define ull unsigned ll
	#define lf double
	#define lb lower_bound 
	#define ub upper_bound 
	#define mp make_pair
	#define File(x,y) freopen(#x,"r",stdin),freopen(#y,"w",stdout)
	#define Fill(x,y) memset(x,y,sizeof x);
	#define Copy(x,y) memset(y,x,sizeof x);
	inline ll read()
	{
		ll ss=0; bool cit=1; char ch;
		while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
		while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
		return cit?ss:-ss;
	}
} using namespace BSS;

const ll N=405;
const ll mod=1e9+7;
ll m,n,ans;
ll a[N],b[N],pos1[N],pos2[N];
ll f1[N][N][N/3],f2[N][N][N/3];
signed main(){
	n=read(); m=n/3;
	for(re i=1;i<=n;i++) a[i]=read(),pos1[a[i]]=i;
	for(re i=1;i<=n;i++) b[i]=read(),pos2[b[i]]=i;
	f1[1][1][0]=1;
	for(re i=1;i<=n+1;i++)
		for(re j=1;j<=n+1;j++)
			for(re k=0;k<=m;k++){
				if(i<=n and f1[i][j][k]){
					if(pos2[a[i]]<j) (f1[i+1][j][k]+=f1[i][j][k])%=mod;
					else{
						(f2[i][j][k]+=f1[i][j][k])%=mod;
						if(k) (f1[i+1][j][k-1]+=f1[i][j][k]*k%mod)%=mod;
					}
				}
				else (ans+=f1[i][j][k]*(!k))%=mod;
				if(j<=n and f2[i][j][k]){
					if(pos1[b[j]]<i) (f2[i][j+1][k]+=f2[i][j][k])%=mod;
					else{
						if(a[i]!=b[j]){
							(f1[i+1][j+1][k+1]+=f2[i][j][k])%=mod;
							if(k) (f2[i][j+1][k-1]+=f2[i][j][k]*k%mod)%=mod;
						}
					}
				}	
			}	
	for(ll i=1;i<=m;i++)
		(ans*=(3*i-1)*(3*i-2)%mod)%=mod;
	printf("%lld",ans%mod);
}

D. [NOI2021]树

想到时间戳但是打不出正解..
打一个时间戳,然后参考题目'染色'即可..
又一次巧妙地将边权转化为了点之间的关系.
如果一条边的两个时间戳不同,那么说明这条边的颜色是黑色的.
首先给每个点都赋予不同的时间戳,因为开始时每条边都是黑色的.
然后考虑将每个变白的链打上同一个时间戳.
如果两个时间戳不一样,说明这条边要统计到答案里.
树剖即可.

关于这道题的数据写一个暴力然后特判一个菊花图就能\(A\)而且跑得比正解还快..我只能说我在只想打\(AC\)解的路上有点固执了.
努力打\(AC\)是不会变的,但是重点是要拿到高分.

posted @ 2021-08-19 18:24  AaMuXiiiiii  阅读(47)  评论(0编辑  收藏  举报