//https://img2018.cnblogs.com/blog/1646268/201908/1646268-20190806114008215-138720377.jpg

2022NOIP解题报告

T1

一拿到题看着挺简单,但考试的时候做了三个小时,最后数组忘清空了100->1
我看他们的做法都比我的简单,也比我的快一点,但是我这个做法在考试的时候是可以A掉T1的。
首先需要两个前缀和来维护当前点向下(\(s1\))和向右(\(s2\))(均不包括自身)分别有几个连续的0。
考虑一下,如果要是想计算以当前点为C或F的左上角,如何利用这两个前缀和进行计算。
先说C;
首先要保证当前点不为1且右方连续的0有1个及以上,然后,我们可以根据样例得知,向下的连续零要大于等于2然后每一行能与第一行匹配的C的个数就是当前点\(s1-1\),F也是同理,只是与C相比多了下面的一条线,处理好即可。

code:

#include<bits/stdc++.h>
#define int long long
#define P 998244353
#define endl '\n'
#define N 1100
using namespace std;
int T,id,n,m,C,F,ansc,ansf;
int s1[N][N],s2[N][N],s3[N][N],s4[N][N];
char a[N][N];
void work1()
{
	while(T--)
	{
		for(int i=1;i<=n;i++)
		  for(int j=1;j<=m;j++)
		    s1[i][j]=s2[i][j]=s3[i][j]=s4[i][j]=0;
		ansc=0;ansf=0;
		cin>>n>>m>>C>>F;
		for(int i=1;i<=n;i++)
		  for(int j=1;j<=m;j++)
		    cin>>a[i][j];
		if(C==0&&F==0)
		{
			cout<<"0 0"<<endl;
			continue;
		}
		for(int i=n;i>=1;i--)
		{
			int ccc=0;
			for(int j=m;j>=1;j--)
			{
				if(a[i][j]=='0')s1[i][j]=ccc++;
				else ccc=0;
			}
		}
		for(int j=m;j>=1;j--)
		{
			int ccc=0;
			for(int i=n;i>=1;i--)
			{
				if(a[i][j]=='0')s2[i][j]=ccc++;
				else ccc=0;
			}
		}
		for(int i=1;i<=n;i++)
		  for(int j=1;j<=m;j++)
			for(int o=i+2;o<=i+s2[i][j];o++)
			  s3[i][j]=(s3[i][j]+s1[o][j]*s1[i][j])%P,
			  s4[i][j]=(s4[i][j]+s1[o][j]*(s1[i][j]*(s2[i][j]-o+i)%P))%P;
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=m;j++)
			  ansc=(ansc+s3[i][j])%P,
			  ansf=(ansf+s4[i][j])%P;
		}
		cout<<(ansc%P)<<" ";
		if(F==0)
		{
			cout<<0<<endl;
			continue;
		}
		cout<<(ansf%P)<<endl;
	}
}
signed main()
{
	cin>>T>>id;
	work1();
	return 0;
}

T2

考试没看懂,打了半个多小时没打出来去看别的了。
爆零了

T3

考试看了一遍后感觉不如T4的部分分好拿,所以没有去花费太多时间。
考试得了0分。
image
code:

#include<bits/stdc++.h>
using namespace std;
template<typename T>void rd(T&x){
	x=0;int f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=x*10+c-48;c=getchar();}
	x*=f;
}
typedef long long ll;
const int N=5e5+10,M=1e6+10,E=M*2;
const ll mod=1e9+7;
ll qpow(ll x,ll y){
	ll z=1;
	while(y){
		if(y&1)z=z*x%mod;
		x=x*x%mod;
		y>>=1;
	}
	return z;
}
const int half=qpow(2,mod-2);
int n,m,deg[N];
struct T{
	int e=1,n[E],t[E],h[N];
	void lnk(int x,int y){
		n[++e]=h[x];
		t[e]=y;
		h[x]=e;
	}
}g,h;
int c,d[N],l[N];
int t,s[N];
int p,b[N],z[N];
void tarj(int x,int f){
	d[x]=l[x]=++c;
	s[t++]=x;
	for(int i=g.h[x];i;i=g.n[i]){
		int y=g.t[i];
		if(!d[y]){
			tarj(y,x);
			l[x]=min(l[x],l[y]);
		}else if(y!=f)l[x]=min(l[x],d[y]);
	}
	if(d[x]==l[x]){
		++p;
		do{
			--t;
			b[s[t]]=p;
			++z[p];
		}while(s[t]!=x);
	}
}
ll dp[N],ans;
void dfs(int x,int f){
	dp[x]=qpow(2,z[x]-1);
	for(int i=h.h[x];i;i=h.n[i]){
		int y=h.t[i];
		if(y==f)continue;
		dfs(y,x);
		dp[x]=dp[x]*(dp[y]+1)%mod;
	}
	dp[x]=(dp[x]+mod-half)%mod;
	ans=(ans+dp[x])%mod;
}
int main(){
	rd(n);rd(m);
	for(int i=1,u,v;i<=m;++i)rd(u),rd(v),g.lnk(u,v),g.lnk(v,u),++deg[u],++deg[v];
	tarj(1,1);
	for(int x=1;x<=n;++x){
		for(int i=g.h[x];i;i=g.n[i]){
			int y=g.t[i];
			if(b[x]!=b[y])h.lnk(b[x],b[y]);
		}
	}
	dfs(1,1);
	printf("%lld",(ans+dp[1])*qpow(2,m)%mod);
}
posted @ 2022-12-21 15:29  北烛青澜  阅读(65)  评论(0)    收藏  举报