noip模拟10

T1

数组开小痛失 \(30pts\) ...

\(60pts\) 做法:

按题目要求中 \((a,b,x,y)\) 的定义

预处理出 \(Pre_{i,j}\) 表示 \((1,1,i,j)\) 矩形的大小

容易推得

\((x,y,a,b)=(k+pre[a][b]-pre[x-1][b]-pre[a][y-1]+pre[x-1][y-1])mod(k)\)

对于\(n*m<=300\)的直接暴力枚举左上右下点求得个数,得 \(60pts\)

\(75pts\) :

\(60pts\) 的基础上,注意到有全部相等的特殊性质,故直接\(n*m\)枚举矩形的形状,符合条件的直接加上这种形状矩形的个数即可(注意开\(longlong\)

\(100pts\) :

开一个大小为 \(k\)\(cnt\) 数组表示有多少个从第一列开始的矩形的和在膜 \(k\) 意义下等于 \(cnt_{i}\)

先枚举上边界在枚举下边界再从左往右递推即可,用栈清空节约时间。

Code

#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#include<stack>
namespace EMT{
	#define int long long
	inline long long read(){long long x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline void file(){
		freopen("in.in","r",stdin);
		freopen("my.out","w",stdout);
	}
	const int N=410;int n,m,k;
	typedef long long ll;
	inline bool is(ll x){return k*(x/k)==x;}
	inline void pi(ll x){pf("%lld ",x);}inline void pn(){pf("\n");}
	int pre[N][N],ls[N];ll ans,cnt[1000100];std::stack<int>s;
	inline int sum(int x,int y,int a,int b){
		return (k+pre[a][b]-pre[x-1][b]-pre[a][y-1]+pre[x-1][y-1])%k;
	}
	inline short main(){
		int c=1,ls=0;
		n=read(),m=read(),k=read();
		F(i,1,n)F(j,1,m){int x=read();if(ls&&ls!=x)c=0;ls=x;pre[i][j]=((ll)pre[i][j-1]+x)%k;}
		F(i,2,n)F(j,1,m)pre[i][j]=((ll)pre[i][j]+pre[i-1][j])%k;
		if(c){
			F(i,1,n)F(j,1,m)if(is(pre[i][j]))ans+=(ll)(n-i+1)*(m-j+1);
			pi(ans);return 0;
		}
		F(i,1,n){
			F(j,i,n){
				int t;while(!s.empty()){int x=s.top();s.pop();cnt[x]=0;}
				cnt[0]=1;
				F(l,1,m){
					t=sum(i,1,j,l);s.push(t);
					ans+=cnt[t];++cnt[t];
				}
			}
		}
		pi(ans);
		return 0;
	}
}
signed main(){return EMT::main();}

T2

还是 \(wtcl\),推了一整节考试没推出来 \(dp\) 式子...

既然不会 \(dp\) ,那就贪心。

将深度大的点排在前面,将它的 \(k\) 级父亲点亮是最优的,如果这个点已经标记过了,就可以直接跳过。

我们规定一个函数 \(out\) 来标记符合条件的点, \(dfs\) 求出每个点的深度,用结构体存储深度和编号,排序,并利用倍增函数 \(getfa\)\(k\) 级父亲即可。

Code



#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<stack>
namespace EMT{
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline void file(){
		freopen("in.in","r",stdin);
		freopen("my.out","w",stdout);
	}
	const int N=1e5+100;int head[N],co;int n,k;struct node{int next,to;}e[N<<1];
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	inline void add(int next,int to){e[++co].next=head[next],e[co].to=to;head[next]=co;}
	bool light[N];
	int deep[N],fa[N][22];
	struct tree{
		int dep,id;
		bool operator<(const tree &a)const{return dep>a.dep;}
	}t[N];
	inline void out(int x,int dep,int fa){
		light[x]=1;if(dep==k)return;
		for(register int i=head[x];i;i=e[i].next){
			int j=e[i].to;if(j==fa)continue;
			out(j,dep+1,x);
		}
	}
	inline void dfs(int x,int f){
		t[x].id=x;
		for(register int i=head[x];i;i=e[i].next){
			int j=e[i].to;if(j==f)continue;
			deep[j]=deep[x]+1;t[j].dep=deep[j];
			fa[j][0]=x;for(register int i=1;(1<<i)<=deep[j];i++)fa[j][i]=fa[fa[j][i-1]][i-1];
			dfs(j,x);
		}
	}
	inline int getfa(int x,int k){
		if(k>=deep[x])return 1;
		D(i,20,0)if((1<<i)<=k){x=fa[x][i];k-=(1<<i);}
		return x;
	}
	inline short main(){
		//file();
		n=read();k=read();read();
		F(i,1,n-1){
			int x=read(),y=read();
			add(x,y);add(y,x);
		}
		dfs(1,0);
		std::sort(t+1,t+n+1);
		int cnt=0;
		F(i,1,n){
			if(light[t[i].id])continue;
			int fa=getfa(t[i].id,k);
			out(fa,0,0);cnt++;
		}
		pi(cnt);
		return 0;
	}
}
signed main(){return EMT::main();}

T3

利用差分数组和bfs来求得消除\(i,j\)的最小花费\(cost_{i,j}\)

最后再利用\(bfs\)节约点时间求得最小步数即可。

Code

#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<stack>
namespace EMT{
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline void file(){
		freopen("in.in","r",stdin);
		freopen("my.out","w",stdout);
	}
    const int N=4e5+100,maxn=0x3f3f3f3f;std::queue<int>q;
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	int n,m,k,op[41],cnt,a[40],b[40],c[N],dis[N],cost[40][40];
	const int M=1<<17;int f[M];bool v[M];
	inline void bfs(int x){
		memset(dis,0x3f,sizeof(dis));
		q.push(op[x]);dis[op[x]]=0;
		while(!q.empty()){
			int u=q.front();q.pop();
			F(i,1,m){
				int l=u-b[i],r=u+b[i];
				if(l>=1&&dis[l]==maxn){
					dis[l]=dis[u]+1;
					q.push(l);
				}
				if(r<=1+n&&dis[r]==maxn){
					dis[r]=dis[u]+1;
					q.push(r);
				}
			}
		}
		F(i,1,cnt){
			if(dis[op[i]]!=maxn){
				cost[x][i]=dis[op[i]];
			}
		}
	}
	inline int min(int a,int b){return a<b?a:b;}
	inline short main(){
		n=read();k=read();m=read();
		F(i,1,k)a[i]=read(),c[a[i]]^=1,c[a[i]+1]^=1;
		F(i,1,m)b[i]=read();
		F(i,1,n+1)if(c[i])op[++cnt]=i;
		memset(cost,0x3f,sizeof(cost));
		memset(f,0x3f,sizeof(f));
		F(i,1,cnt)bfs(i);
		int st=(1<<cnt)-1;
		f[st]=0;
		q.push(st);
		while(!q.empty()){
			int i=q.front();q.pop();
			F(j,1,cnt){
				if(!(i&(1<<(j-1))))continue;
				F(t,j+1,cnt){
					if(!(i&(1<<(t-1))))continue;
					int x=~(~(i)|(1<<(j-1))|(1<<(t-1)));
					f[x]=min(f[x],f[i]+cost[j][t]);
					if(!v[x])q.push(x),v[x]=1;
				}
			}
		}
		pi(f[0]);pn();
		return 0;
	}
}
signed main(){return EMT::main();}

posted @ 2021-06-28 20:25  letitdown  阅读(52)  评论(0编辑  收藏  举报