Loading

Noip模拟99 2021.11.16

以此纪念考场时间分配炸裂的一场考试

亏得\(T2\)给的暴力分数多。。。。

一写就是三个多小时,当时不知道怎么想的,不过再也不敢死磕一道题了呜呜呜

当时考场上最后想到了一种八个状态的\(dp\)转移,然后也因此把写\(T1\)的时间搞到了三个多小时

然而在考试后调试代码的时候发现是假的,所以,以后考场上不能再刚题了!!!

需要重新制定一下考试策略了,如果是\(dp\)而且发现并没有什么特别明显的思路就先跳过

在拿到所有的能拿到的分数再回来做这道题

T1 法阵

想不到这道题排在了正常考试\(T3\)的位置,$CF$3100的题真不是给人写的。。。

题解讲的比我明白,直接给链接了,戳着李

magic
#include<bits/stdc++.h>
#define int long long
using namespace std;FILE *wsn;
auto 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<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
};
const int NN=5005,mod=998244353;
int n,m,rng,ans;
int h[NN],v[NN];
auto qmo=[](int a,int b,int ans=1){
	for(;b;b>>=1,a=a*a%mod)if(b&1)ans=ans*a%mod;
	return ans;
};
auto prework=[](){
	h[0]=h[1]=1; v[0]=v[1]=1;for(int i=2;i<NN;i++)h[i]=h[i-1]*i%mod;
	v[NN-1]=qmo(h[NN-1],mod-2);for(int i=NN-2;i>=2;i--)v[i]=v[i+1]*(i+1)%mod;
};
auto C=[](int n,int m){return (n<m||n<0||m<0)?0:h[n]*v[n-m]%mod*v[m]%mod;};
auto W=[](int x,int y){return C(x+y,x);};
namespace WSN{
	inline short main(){
		wsn=freopen("magic.in","r",stdin);
		wsn=freopen("magic.out","w",stdout);
		n=read(); m=read(); prework();
		for(int i=1;i<m;i++){
			int sum=0;
			for(int j=1;j<n;j++){
				sum=(sum+W(i,j-1)*W(i-1,n-j)%mod)%mod;
				ans=(ans+sum*W(m-i,n-j-1)%mod*W(m-i-1,j)%mod)%mod;
			}
		}
		swap(n,m);
		for(int i=1;i<m;i++){
			int sum=0;
			for(int j=1;j<n;j++){
				ans=(ans+sum*W(m-i,n-j-1)%mod*W(m-i-1,j)%mod)%mod;
				sum=(sum+W(i,j-1)*W(i-1,n-j)%mod)%mod;
			}
		}
		printf("%lld\n",ans*2%mod);
		return 0;
	}
}
signed main(){return WSN::main();}

T2 连通块

这才是真正的\(T1\)

我的做法常数比较大,在于重新建了一个图找直径,其实不用,直接在冰茶姬上面维护就行了

block
#include<bits/stdc++.h>
#define int long long
using namespace std;FILE *wsn;
auto 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<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
};
const int NN=2e5+5;
int n,m;
struct node{int opt,x;}pp[NN];
struct edge{int u,v;}p[NN];
bool del[NN];

#define star(i,x) for(int i=head[x],y=e[i].to;i;i=e[i].next,y=e[i].to)
struct SNOW{int to,next;}e[NN<<1];int head[NN],rp;
auto add=[](int x,int y){
	e[++rp]=SNOW{y,head[x]};head[x]=rp;
	e[++rp]=SNOW{x,head[y]};head[y]=rp;
};

namespace tree_division{
	int fa[NN],son[NN],dep[NN],top[NN],siz[NN],dfn[NN],cnt;
	inline void dfs1(int f,int x){
		fa[x]=f; siz[x]=1; dep[x]=dep[f]+1;
		star(i,x)if(y!=f){
			dfs1(x,y); siz[x]+=siz[y];
			if(siz[son[x]]<siz[y])son[x]=y;
		}
	}
	inline void dfs2(int x,int t){
		dfn[x]=++cnt; top[x]=t;if(son[x]) dfs2(son[x],t);
		star(i,x) if(y!=fa[x]&&y!=son[x]) dfs2(y,y);
	}
	inline int LCA(int x,int y){
		while(top[x]!=top[y]){
			if(dep[top[x]]<dep[top[y]])swap(x,y);
			x=fa[top[x]];
		}if(dfn[x]>dfn[y]) swap(x,y); return x;
	}
	inline int getdis(int x,int y){return dep[x]+dep[y]-dep[LCA(x,y)]*2;}
}using namespace tree_division;

namespace DSU{
	int Fa[NN]; struct kuai{int x,y;}kk[NN];
	inline int getfa(int x){return Fa[x]=(Fa[x]==x)?x:getfa(Fa[x]);}
	inline void merge(int x,int y,int opt){
		x=getfa(x); y=getfa(y);
		if(x==y)return;if(x>y)swap(x,y);
		Fa[y]=x; if(!opt) return;
		kuai k1=kk[x],k2=kk[y];
		int t1=getdis(k1.x,k2.x),t2=getdis(k1.x,k2.y);
		int t3=getdis(k1.y,k2.x),t4=getdis(k1.y,k2.y);
		int t5=getdis(k1.x,k1.y),t6=getdis(k2.x,k2.y);
		int mx=t5; kuai P=k1;
		if(mx<t6)P=k2,mx=t6;
		if(mx<t1)P=kuai{k1.x,k2.x},mx=t1;
		if(mx<t2)P=kuai{k1.x,k2.y},mx=t2;
		if(mx<t3)P=kuai{k1.y,k2.x},mx=t3;
		if(mx<t4)P=kuai{k1.y,k2.y},mx=t4;
		kk[x]=P;
	}
}using namespace DSU;

namespace distanse{
	bool vis[NN]; queue<int>q;
	inline int bfs(int st,int pos=0){
		memset(vis,0,sizeof(vis));
		q.push(st); vis[st]=1;
		while(!q.empty()){
			int x=q.front(); q.pop(); pos=x;
			star(i,x) if(!vis[y]) q.push(y),vis[y]=1;
		}
		return pos;
	}
	inline void maxdis(int x){
		int p1=bfs(x),p2=bfs(p1); x=getfa(x);
		kk[x].x=p1; kk[x].y=p2;
	}
}using namespace distanse;
int ans[NN];
namespace WSN{
	inline short main(){
		wsn=freopen("block.in","r",stdin);
		wsn=freopen("block.out","w",stdout);
		n=read(); m=read();
		for(int i=1;i<=n;i++)Fa[i]=i;
		for(int i=1,u,v;i<n;i++)
			u=read(),v=read(),p[i]=edge{u,v},add(u,v);
		dfs1(0,1); dfs2(1,1);
		rp=0; memset(head,0,sizeof(head));
		for(int i=1,opt,x;i<=m;i++){
			opt=read(),x=read(),pp[i]=node{opt,x};
			if(opt==1) del[x]=1;
		}
		for(int i=1;i<n;i++)if(!del[i])
			add(p[i].u,p[i].v),merge(p[i].u,p[i].v,0);
		memset(del,0,sizeof(del));
		for(int i=1;i<=n;i++)if(!del[getfa(i)])
			del[getfa(i)]=1,maxdis(getfa(i));
		// for(int i=1;i<=n;i++)if(del[i])
		// 	cout<<i<<" "<<kk[i].x<<" "<<kk[i].y<<endl;
		int tot=0;
		for(int i=m;i;i--){
			if(pp[i].opt==1){
				edge now=p[pp[i].x];
				merge(now.u,now.v,1);
			}else{
				kuai now=kk[getfa(pp[i].x)];
				ans[++tot]=max(getdis(pp[i].x,now.y),getdis(pp[i].x,now.x));
			}
		}
		reverse(ans+1,ans+tot+1);
		for(int i=1;i<=tot;i++)printf("%lld\n",ans[i]);
		return 0;
	}
}
signed main(){return WSN::main();}

T3 军队

主要就是用扫描线求出雄性雌性的个数,然后根据两个数差值越小乘积越大进行最优解的贪心即可

本身扫描线是想用珂朵莉树写的,不过显然他被卡了。。。卡的和暴力一个分。。。

然后就是用线段树进行一个标记永久化就可以了

army
#include<bits/stdc++.h>
#define int long long
using namespace std;
namespace AE86{
	FILE *wsn;
	#define gc() p1==p2 and (p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++
	char buf[1<<20],*p1=buf,*p2=buf;
	auto read=[](){
		int x=0,f=1;char ch=gc();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
		while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=gc();} return x*f;
	};
	auto write=[](int x,char opt='\n'){
		char ch[20];short len=0;if(x<0)x=~x+1,putchar('-');
		do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x);
		for(short i=len-1;i>=0;--i){putchar(ch[i]);}putchar(opt);
	};
}using namespace AE86;

const int NN=3e5+5;
int n,m,c,k,q,tmp,a[NN],b[NN],sm1[NN],sm[NN];
struct Update{int l,r,v;};
vector<Update>upd[NN];

struct SNOWtree{
	#define lid (id<<1)
	#define rid (id<<1|1)
	#define mid ((l+r)>>1)
	int sm[NN<<2],mx[NN<<2],ln[NN<<2];
	inline void pushup(int id){
		int tmp=min(sm[lid],sm[rid]);
		sm[lid]-=tmp;sm[rid]-=tmp;
		mx[lid]-=tmp;mx[rid]-=tmp;
		sm[id]+=tmp;
		mx[id]=max(mx[lid],mx[rid])+sm[id];
	}
	inline void build(int id,int l,int r){ln[id]=r-l+1;if(l==r)return;build(lid,l,mid);build(rid,mid+1,r);}
	inline void update(int L,int R,int v,int id=1,int l=1,int r=m){
		if(L<=l&&r<=R) return sm[id]+=v,mx[id]+=v,void();
		if(L<=mid) update(L,R,v,lid,l,mid);
		if(R>mid) update(L,R,v,rid,mid+1,r);
		pushup(id);
	}
	inline int query(int now,int id=1,int l=1,int r=m){
		now+=sm[id];
		if(now>=k) return ln[id];
		if(l==r) return 0;
		int ret=0;
		if(mx[lid]+now>=k) ret+=query(now,lid,l,mid);
		if(mx[rid]+now>=k) ret+=query(now,rid,mid+1,r);
		return ret;
	}
}tr;

namespace WSN{
	inline short main(){
		wsn=freopen("army.in","r",stdin);
		wsn=freopen("army.out","w",stdout);
		n=read();m=read();c=read();k=read();q=read();
		for(int i=1;i<=c;i++){
			int x1=read(),y1=read(),x2=read(),y2=read();
			upd[x1].push_back(Update{y1,y2,1});
			upd[x2+1].push_back(Update{y1,y2,-1});
		}
		tr.build(1,1,m);
		for(int i=1;i<=n;i++){
			for(auto x:upd[i]) tr.update(x.l,x.r,x.v);
			int tmp=tr.query(0);
			a[i]=m-tmp;b[i]=min(a[i],m-a[i]);
		}
		sort(b+1,b+n+1);
		for(int i=1;i<=n;i++)
			sm1[i]=sm1[i-1]+b[i]*b[i],sm[i]=sm[i-1]+b[i];
		while(q--){
			int x=read(),y=read(),my=y/2;
			int pos=upper_bound(b+1,b+n+1,my)-b;
			if(pos==n+1){
				int ans=(sm[n]-sm[n-x])*y-(sm1[n]-sm1[n-x]);
				write(ans);
			}else if(pos<=n-x+1){
				int ans=x*(y-my)*my;
				write(ans);
			}else{
				int ans=(n-pos+1)*(y-my)*my;
				ans+=(sm[pos-1]-sm[n-x])*y-(sm1[pos-1]-sm1[n-x]);
				write(ans);
			}
		}
		return 0;
	}
}
signed main(){return WSN::main();}

T4 棋盘

姑姑孤

posted @ 2021-11-16 21:12  雪域亡魂  阅读(134)  评论(0编辑  收藏  举报