CSP-S模拟21

前言:

论读假题得来的\(80~pts\)

image

以及我们亲爱的晋江文学城:

不是?啊?晋江,你这...对吗?

\(T1:\) 雷暴(storm)

思路:

据说是\(J\)组难度,几乎全切。记录下来每种颜色出现的最上/下/左/右,然后作差平方就好了

代码:

$code$
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e3+5,M=1e5+5,inf=1e5;
int n,m,k,a,lmin[M],lmax[M],rmin[M],rmax[M],s,t;
int main(){
//	freopen("storm.in","r",stdin);
//	freopen("storm.out","w",stdout);
	ios::sync_with_stdio(false);
	cin>>n>>m>>k;
	for(int i=1;i<=k;i++) lmin[i]=rmin[i]=inf;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cin>>a;
			lmin[a]=min(lmin[a],j),lmax[a]=max(lmax[a],j);//最左/右
			rmin[a]=min(rmin[a],i),rmax[a]=max(rmax[a],i);//最上/下
		}
	}
	for(int i=1;i<=k;i++){
		t=max(lmax[i]-lmin[i],rmax[i]-rmin[i])+1;//作差求边长
		s=t*t;//求面积
		cout<<s<<'\n';//输出答案
	}
	return 0;
}

\(T2:\) 神力 (god)

思路:

除了我几乎都想到了\(dp\)做法,但是很显然,正着推的\(dp\)有点假,因为它会算重,因为如果第三\(i\)步到了\(j\),那么在第\(k\)\(k>i\))步到\(j\)的概率就不应该再计入了。因此我们可以倒过来\(dp\)。设\(dp_{i,j}\)表示经过后\(i\)个操作走到了距离原点为\(j\)的概率。此时唯一受影响的就是\(j=0\)的情况,强制令\(dp_{i,0}=1\)即可。

代码:

$code$
#include<iostream>
#define int long long
using namespace std;
const int N=5200,mod=1e9+7;
int n,p,q,a[N],f[N][N<<1];
inline int qpow(int x,int y){
	int res=1;
	while(y){
		if(y&1) res=(res*x)%mod;
		x=(x*x)%mod;
		y>>=1;
	}return res;
}//快速幂 
signed main(){
//	freopen("god.in","r",stdin);
//	freopen("god.out","w",stdout);
	ios::sync_with_stdio(false);
	cin>>n>>p;
	p=p*qpow(100,mod-2)%mod;q=(1-p+mod)%mod;//分数取模 
	for(int i=1;i<=n;i++) cin>>a[i];
	f[n+1][n+1]=1;
	for(int i=n;i>=1;i--){//倒推 
		for(int j=1;j<=(n<<1)+1;j++) f[i][j]=(f[i+1][j]*p+f[i+1][j-a[i]]*q)%mod;//很显然的递推式 
		f[i][n+1]=1;//强制为 1 
	}
	for(int i=1;i<=(n<<1)+1;i++) cout<<f[1][i]<<" ";//输出答案 
	return 0;
}

\(T3:\) 之缘千里(fate)

思路:

一道如果读真题我不一定会做,但是读假题得\(80~pts\)的题。

我们可以将这题看做是左括号的位置与\(1,3,5,7,...,2n-1\)的位置匹配。遍历\(2n\)个位置,看当点位置对应的会面那个位置能否作为左括号,若能,则从可以匹配的空缺位置中找到最小的两个匹配(满足题目字典序最小的要求)。

代码:

$code$
#include<iostream>
#include<set>
using namespace std;
const int N=2e6+5;
int n,x,fir[N],sec[N];bool flag[N];set<int> s;
int main(){
//	freopen("fate.in","r",stdin);
//	freopen("fate.out","w",stdout);
	ios::sync_with_stdio(false);
	cin>>n;
	for(int i=1;i<=(n<<1);i++){
		cin>>x;
		if(fir[x]) sec[fir[x]]=i;//第二次出现的位置 
		else fir[x]=i;//第一次出现的位置 
	}
	for(int i=1;i<=(n<<1);i+=2) s.insert(i);//{1,3,5,7,...2*n-1}
	for(int i=1;i<=(n<<1);i++){
		if(sec[i]&&s.size()&&*s.rbegin()>=sec[i]){//有后面对应的数字&&还有位置填&&最后的空位在后面对应数字的后面(长难句,寄几分析去叭) 
			s.erase(s.lower_bound(sec[i]));//把后面的那个位置占了 
			if(*s.rbegin()>=i) s.erase(s.lower_bound(i));//把现在这个位置占了 
			else{//前后位置不匹配 
				cout<<":(";//赛时题面里给的两个符号里面有空格啊啊啊 
				return 0;
			}
			flag[i]=flag[sec[i]]=1;//标注一下 
		}
	}
	if(s.size()){
		cout<<":(";
		return 0;
	}//没能完全匹配上 
	for(int i=1;i<=(n<<1);i++) //输出答案 
		if(flag[i]) cout<<"(";
		else cout<<")";
	return 0;
}

\(T4:\) 怒气冲天( rectangle)

思路:

借鉴的一位学长的,学长安康,学长您吉祥,学长您别生气

其实我要写的好像跟学长的也会是差不多的(毕竟是借鉴的【逃】),那就不写了???我觉得思路还是挺好懂的,就是代码实现可能困难了些,应该粘个代码就行了吧(其实也是粘学长的,微微动了一点点)

$code$
#include<bits/stdc++.h>
#define int long long
#define lowbit(x) (x&-x)
#define lid id<<1
#define rid id<<1|1
using namespace std;
const int maxn=4e5+5;
int n,lsh[maxn],tot,cnt,d[maxn],ans,res;
struct node{
	int x,y1,y2,typ,id;
	node(int x=0,int y1=0,int y2=0,int typ=0,int id=0):x(x),y1(y1),y2(y2),typ(typ),id(id){}
	bool operator<(const node &b)const{
		return (x<b.x)||(x==b.x&&typ<b.typ);
	}
}a[maxn];
struct BIT{
	int tr[maxn];
	void add(int p,int v){
		for(;p<=tot;p+=lowbit(p)) tr[p]+=v;
	}
	int query(int p){
		int res=0;
		for(;p;p-=lowbit(p)) res+=tr[p];
		return res;
	}
};
struct DS{
	BIT L,R;
	void add(int l,int r,int v){
		L.add(l,v),R.add(r,v);
	}
	int query(int l,int r){
		return L.query(r)-R.query(l-1);
	}
}D1,D2,D3;
//树状数组维护扫描线 

struct seg{
	int ll,rr,sum;
	seg(int ll=0,int rr=0,int sum=0):ll(ll),rr(rr),sum(sum){}
	seg operator+(const seg &x)const{
		return seg(ll+x.ll,rr+x.rr,sum+x.sum+rr*x.ll);
	}
};
struct STR{
	#define ll(id) tr[id].ll
	#define rr(id) tr[id].rr
	#define sum(id) tr[id].sum	
	seg tr[maxn<<2];
	void pushup(int id){
		tr[id]=tr[lid]+tr[rid];
	}
	void addl(int id,int l,int r,int p,int v){
		if(l==r){
			ll(id)+=v;
			return ;
		}
		int mid=(l+r)>>1;
		if(p<=mid) addl(lid,l,mid,p,v);
		else addl(rid,mid+1,r,p,v);
		pushup(id);
	}
	void addr(int id,int l,int r,int p,int v){
		if(l==r){
			rr(id)+=v;
			return ;
		}
		int mid=(l+r)>>1;
		if(p<=mid) addr(lid,l,mid,p,v);
		else addr(rid,mid+1,r,p,v);
		pushup(id);
	}
	seg query(int id,int L,int R,int l,int r){
		if(L>=l&&R<=r) return tr[id];
		int mid=(L+R)>>1;
		if(r<=mid) return query(lid,L,mid,l,r);
		if(l>mid) return query(rid,mid+1,R,l,r);
		return query(lid,L,mid,l,r)+query(rid,mid+1,R,l,r);
	}
}S;
//线段树 

signed main(){
	ios::sync_with_stdio(0),cin.tie(0);
	cin>>n;
	for(int i=1,x1,x2,y1,y2;i<=n;i++){
		cin>>x1>>x2>>y1>>y2;
		lsh[++tot]=y1,lsh[++tot]=y2;
		a[++cnt]=node(x1,y1,y2,0,i);
		a[++cnt]=node(x2,y1,y2,1,i);
	}
	sort(lsh+1,lsh+tot+1);
	tot=unique(lsh+1,lsh+tot+1)-lsh-1;
	for(int i=1;i<=cnt;i++){
		a[i].y1=lower_bound(lsh+1,lsh+tot+1,a[i].y1)-lsh;
		a[i].y2=lower_bound(lsh+1,lsh+tot+1,a[i].y2)-lsh;
	}
	sort(a+1,a+cnt+1);
	ans=n*(n-1)*(n-2)/6;
	for(int i=1,l,r,typ,id;i<=cnt;i++){
		l=a[i].y1,r=a[i].y2,typ=a[i].typ,id=a[i].id;
		if(typ){
			D2.add(l,r,1);
			d[id]+=D1.query(l,r)-1;
			S.addl(1,1,tot,l,-1);
			S.addr(1,1,tot,r,-1);
			D3.add(l,r,-1);
		}else{
			D1.add(l,r,1);
			d[id]-=D2.query(l,r);
			int tmp=D3.query(l,r);
			ans-=tmp*(tmp-1)/2-S.query(1,1,tot,l,r).sum;
			S.addl(1,1,tot,l,1);
			S.addr(1,1,tot,r,1);
			D3.add(l,r,1);
		}
	}
	for(int i=1;i<=n;i++) res+=(n-2)*d[i]-d[i]*(d[i]-1);
	cout<<ans-res/2;
	return 0;
}
posted @ 2025-09-14 20:30  晏清玖安  阅读(36)  评论(0)    收藏  举报