【LGR-059】洛谷7月月赛题解

传送门

比赛的时候正在大巴上,笔记本没网又没电(不过就算有我估计也不会打就是了)

\(A\)

咕咕

const int N=(1<<10)+5;
int a[N][N],n;
void solve(int x,int y,int p){
	if(p==1)return a[x][y]=1,void();
	p>>=1;
	solve(x+p,y,p),solve(x,y+p,p),solve(x+p,y+p,p);
}
int main(){
	cin>>n,n=(1<<n);
	solve(1,1,n);
	fp(i,1,n)fp(j,1,n)printf("%d%c",a[i][j]," \n"[j==n]);
	return 0;
}

\(B\)

咕咕


const int N=1e5+5;
int a[N],b[N],nxt[N],Pre[N],vis[N],n;
inline void del(R int x){Pre[nxt[x]]=Pre[x],nxt[Pre[x]]=nxt[x];}
int main(){
	scanf("%d",&n);
	fp(i,1,n)scanf("%d",&a[i]),b[a[i]]=i,Pre[i]=i-1,nxt[i]=i+1;
	fd(i,n,1)if(!vis[i]&&nxt[b[i]]!=n+1){
		printf("%d %d ",i,a[nxt[b[i]]]),vis[i]=vis[a[nxt[b[i]]]]=1;
		del(b[i]),del(nxt[b[i]]);
	}
	return 0;
}

\(C\)

对于每一对逆序对\((i,j)\)要加上\(i\times (n-j+1)\),树状数组维护即可,注意这个会爆\(long\ long\)所以得开\(\_\_int128\)

//quming
#include<bits/stdc++.h>
#define R register
#define ll __int128
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
//typedef long long ll;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
    R int res,f=1;R char ch;
    while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
    for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
    return res*f;
}
inline void print(R ll x){if(x>9)print(x/10);putchar(x%10+48);}
const int N=1e6+5;
ll c[N],res;int a[N],b[N],n,m;
inline void add(R int x,R int y){for(;x<=m;x+=x&-x)c[x]+=y;}
inline ll query(R int x){R ll res=0;for(;x;x-=x&-x)res+=c[x];return res;}
int main(){
//	freopen("testdata.in","r",stdin); 
	n=read();
	fp(i,1,n)a[i]=b[i]=read();
	sort(b+1,b+1+n),m=unique(b+1,b+1+n)-b-1;
	fd(i,n,1){
		a[i]=lower_bound(b+1,b+1+m,a[i])-b;
		res+=query(a[i]-1)*i,
		add(a[i],n-i+1);
	}
//	printf("%lld\n",res);	
	print(res);
	return 0;
}

\(D\)

转移方程推出来之后暴力都写不对可海星……

先把所有区间按右端点排序,发现不允许存在一个位置被覆盖三次及以上,且为了不是森林每个节点必须和其他节点中的至少一个有交

\(f_{i,j}\)表示考虑到第\(i\)个区间,且选择的上一个区间为\(j\)的方案数,边界条件为\(f_{i,0}=1\)

转移分两种情况,一种是\(r[j]\geq l[i]\)\(l[j]<l[i]\),那么假设此时从\(f_{j,k}\)转移过来,则必须满足的条件是\(r[k]<l[i]\),即可以写成

\[f_{i,j}=\sum_{r[k]<l[i]}f_{j,k} \]

另一种情况是\(r[j]\geq l[i]\)\(l[j]\geq l[i]\),那么就不能从\(f[j][k]\)转移而是应该从\(f[i][k]\)进行转移,且需要满足\(r[k]<l[i]\),即

\[f_{i,j}=\sum_{r[k]<l[j]}f_{i,k} \]

这两个都可以用树状数组维护

//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int P=1e9+7;
inline void upd(R int &x,R int y){(x+=y)>=P?x-=P:0;}
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
	R int res=1;
	for(;y;y>>=1,x=mul(x,x))(y&1)?res=mul(res,x):0;
	return res;
}
const int N=4005;
int l[N],r[N],las[N],id[N],f[N][N],n,mx,res;
struct BIT{
	int c[N];
	inline void ins(R int x,R int y){for(++x;x<=mx;x+=x&-x)upd(c[x],y);}
	inline int query(R int x){R int res=0;for(++x;x;x-=x&-x)upd(res,c[x]);return res;}
}bi[N];
inline bool cmp(const int &x,const int &y){return r[x]==r[y]?l[x]<l[y]:r[x]<r[y];}
int main(){
//	freopen("testdata.in","r",stdin);
	scanf("%d",&n);
	fp(i,1,n)scanf("%d%d",&l[i],&r[i]),id[i]=i,cmax(mx,r[i]+1);
	sort(id+1,id+1+n,cmp);
	las[1]=1;
	for(R int i=2,ql,qr,qm,ans;i<=n;++i){
		ql=1,qr=i-1,ans=i;
		while(ql<=qr){
			qm=(ql+qr)>>1;
			r[id[qm]]>=l[id[i]]?(ans=qm,qr=qm-1):ql=qm+1;
		}
		las[i]=ans;
	}
	fp(i,1,n)f[i][0]=1,bi[i].ins(0,1),++res;
	fp(i,2,n)fp(j,las[i],i-1){
		f[i][j]=(l[id[i]]<=l[id[j]]?bi[i].query(l[id[j]]-1):bi[j].query(l[id[i]]-1));
		if(f[i][j])bi[i].ins(r[id[j]],f[i][j]),upd(res,f[i][j]);
//		printf("%d %d %d\n",i,j,f[i][j]);
	}
	printf("%d\n",res);
	return 0;
}
posted @ 2019-07-20 19:16  源曲明  阅读(171)  评论(0编辑  收藏  举报