【简要题解】洛谷 7 月月赛 Div.1

【简要题解】洛谷 7 月月赛 Div.1

P6687 论如何玩转 Excel 表格

把两个状态的每偶数列上下交换一下,旋转操作就变成邻项交换了。

//@winlere
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<map>
#include<unordered_map>

using namespace std; typedef long long ll;
int qr(){
	int ret=0,c=getchar(),f=0;
	while(!isdigit(c)) f|=c==45,c=getchar();
	while( isdigit(c)) ret=ret*10+c-48,c=getchar();
	return f?-ret:ret;
}
const int maxn=1e6+5;
int a[2][maxn],b[2][maxn],id;
vector< pair<int,int> > A,B;
unordered_map< ll, int > qwq;
int seg[maxn],data[maxn],n;

void add(int pos,int val){
	for(int t=pos;t<=n;t+=t&-t) seg[t]+=val;
}

int que(int pos){
	int ret=0;
	for(int t=pos;t>0;t-=t&-t) ret+=seg[t];
	return ret;
}

int main(){
	n=qr(); 
	for(int t=0;t<2;++t)
		for(int i=1;i<=n;++i) a[t][i]=qr();
	for(int t=0;t<2;++t)
		for(int i=1;i<=n;++i) b[t][i]=qr();
	for(int t=1;t<=n;++t){
		if(t&1) A.push_back({a[0][t],a[1][t]});
		else A.push_back({a[1][t],a[0][t]});
		if(t&1) B.push_back({b[0][t],b[1][t]});
		else B.push_back({b[1][t],b[0][t]});
	}
	qwq.reserve(n<<1);
	for(int t=1;t<=n;++t) qwq[((ll)B[t-1].first<<30)+B[t-1].second]=t;
	for(int t=1;t<=n;++t){
		auto g=qwq.find(((ll)A[t-1].first<<30)+A[t-1].second);
		if(g==qwq.end()) return puts("dldsgay!!1"),0;
		data[t]=g->second;
	}
	ll ans=0;
	for(int t=1;t<=n;++t)
		ans+=t-1ll-que(data[t]),add(data[t],1);
	printf("%lld\n",ans);
	return 0;
}


P6688 可重集

将数字\(i\)变成\(x^{a_i}\),设\(F(l,r)=\sum_{i\in[l,r]}x^{a_i}\)。判断两个是否本质相同变成了判断\(F(l,r)=F(L,R)\times x^{\min(l,r)-\min(L,R)}\),哈希下就行。注意到种子要比\(a_i\)

三哈,二哈,单哈都可以过

//@winlere
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>

using namespace std; typedef long long ll;
int qr(){
	int ret=0,c=getchar(),f=0;
	while(!isdigit(c)) f|=c==45,c=getchar();
	while( isdigit(c)) ret=ret*10+c-48,c=getchar();
	return f?-ret:ret;
}
const int maxn=1e6+5;

const ll mod1=1e18+3;
const ll mod2=207132529660813483ll;
const ll mod3=14285714285715727ll;
const ll seed1=19260817;
const ll seed2=19491001;
const ll seed3=9137669;
typedef ll E;

ll MOD1(const ll&a){return a>=mod1?a-mod1:a;}
ll MOD1(const ll&a,const ll&b){return (__int128)a*b%mod1;}

E mi[maxn],seed(seed1);
int a[maxn],n,m;

namespace QWQ{
#define mid ((l+r)>>1)
#define lef l,mid,pos<<1
#define rgt mid+1,r,pos<<1|1
	int seg[maxn<<2];
	E f[maxn<<2];
	void pp(int pos){seg[pos]=min(seg[pos<<1],seg[pos<<1|1]);f[pos]=MOD1(f[pos<<1]+f[pos<<1|1]);}
	void build(int l,int r,int pos){
		if(l==r) return seg[pos]=a[l],f[pos]=mi[a[l]],void();
		build(lef); build(rgt); pp(pos);
	}
	void upd(int p,int v,int l,int r,int pos){
		if(p<l||p>r) return;
		if(l==r) return seg[pos]=v,f[pos]=mi[v],void();
		if(p<=mid) upd(p,v,lef);
		else upd(p,v,rgt);
		pp(pos);
	}
	pair<int,E> que(int L,int R,int l,int r,int pos){
		if(L>r||R<l) return {1e9,0};
		if(L<=l&&r<=R) return {seg[pos],f[pos]};
		auto t1=que(L,R,lef),t2=que(L,R,rgt);
		return {min(t1.first,t2.first),MOD1(t1.second+t2.second)};
	}
#undef mid
#undef lef
#undef rgt
}

int main(){
	n=qr(),m=qr();
	mi[0]={1};
	for(int t=1;t<=1e6;++t) mi[t]=MOD1(mi[t-1],seed);
	for(int t=1;t<=n;++t)
		a[t]=qr();	
	QWQ::build(1,n,1);
	for(int t=1;t<=m;++t){
		int op=qr();
		if(op==0){
			int x=qr(),y=qr();
			QWQ::upd(x,y,1,n,1);
		}
		if(op==1){
			int l=qr(),r=qr(),L=qr(),R=qr();
			auto LL=QWQ::que(l,r,1,n,1),RR=QWQ::que(L,R,1,n,1);
			E t1=LL.second,t2=RR.second;
			int TT1=LL.first,TT2=RR.first;
			if(TT1>TT2) t2=MOD1(t2,mi[TT1-TT2]);
			if(TT1<TT2) t1=MOD1(t1,mi[TT2-TT1]);
			if(t1==t2) puts("YES");
			else puts("NO");
		}
	}
	return 0;
}

P6689 序列

任何一个有\(i\)个右括号的括号序列被那个算法生成的概率是一样的,先设\(dp(i,j)\)表示已经填了\(i\)个括号其中\(j\)个是左括号的概率。

转移是

\[dp(i,j)={n-i+1\over n}dp(i-1,j-1)+\sum_{j=i}^n { j\times (j-1)\times (j-2)\dots \times i=j^{\underline {j-i+1}} \over n^{j-i+2}}(n-i+1) \]

可以简单做到\(O(n^2)\)

现在还少一个东西,那就是一个有\(f_j=j\)个右括号的长度为\(n\)的括号序列期望有多少匹配(括号匹配指方案数是卡特兰数那种匹配)数,枚举一对括号匹配在哪个地方并且产生一的贡献,可以发现这一对括号匹配之间必须完美匹配,方案数是卡特兰数。

\[f_j=\sum_{i=2}^n \sum_{j=0}^{\lfloor{i-2\over 2}\rfloor} C_j {n-2j-2\choose t-1-j}= \sum_{j=0}^{\lfloor{n-2\over 2}\rfloor} C_j (n-(2j-2)+1){n-2j-2\choose t-1-j} \]

复杂度\(O(n^2)\)

//@winlere
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<initializer_list>

using namespace std; typedef long long ll;
int qr(){
	int ret=0,c=getchar(),f=0;
	while(!isdigit(c)) f|=c==45,c=getchar();
	while( isdigit(c)) ret=ret*10+c-48,c=getchar();
	return f?-ret:ret;
}
const int maxn=5015;
const int mod=998244353;
int jc[maxn<<1],inv[maxn<<1],invc[maxn<<1],dp[maxn][maxn],f[maxn<<1],temp[maxn],mi[maxn];
int MOD(const int&x,const int&y){return 1ll*x*y%mod;}
int MOD(const int&x){return x>=mod?x-mod:x;}
int MOD(const initializer_list<int>&ve){int ret=1;for(auto t:ve) ret=MOD(ret,t); return ret;}

int ksm(const int&ba,const int&p){
	int ret=1;
	for(int t=p,b=ba;t;t>>=1,b=MOD(b,b))
		if(t&1) ret=MOD(ret,b);
	return ret;		
}
void pre(const int&n){
	jc[0]=inv[0]=1; jc[1]=inv[1]=invc[1]=1;
	for(int t=2;t<=n;++t) jc[t]=MOD(jc[t-1],t),invc[t]=MOD(invc[mod%t],mod-mod/t),inv[t]=MOD(inv[t-1],invc[t]);
}

int c(const int&n,const int&m){return n<m||m<0?0:MOD(jc[n],MOD(inv[n-m],inv[m]));}
int cat(int n){return MOD(c(2*n,n),invc[n+1]);}

int main(){
	pre(1e4+5);
	int n=qr(),k=qr();
	dp[0][0]=1; mi[0]=1;
	for(int t=1;t<=n+5;++t) mi[t]=MOD(mi[t-1],invc[n]);
	for(int t=1;t<=k;++t){
		for(int i=n;i;--i) temp[i]=MOD(MOD({dp[t-1][i],jc[i],mi[i+2]})+temp[i+1]);
		for(int i=1,g=n;i<=n;++i,g=MOD(g,n)){
			int ret=0;			
			ret=MOD(ret+MOD({dp[t-1][i-1],n-i+1,invc[n]}));
			ret=MOD(ret+MOD({temp[i],n-i+1,g,inv[i-1]}));
			dp[t][i]=ret;
		}
	}
	int ans=0;
	for(int t=0;t<=n;++t){
		int ret=0;
		for(int j=0;j<=n/2-1;++j){
			int sav=MOD({cat(j),n-2*j-1,c(n-2*j-2,t-1-j)});
			ret=MOD(ret+sav);
		}
		ans=MOD(ans+MOD({inv[n],jc[t],jc[n-t],dp[k][t],ret,2}));
	}
	printf("%d\n",ans);
	return 0;
}


P6690 一次函数

你觉得我会?

posted @ 2020-07-25 22:26  谁是鸽王  阅读(401)  评论(0编辑  收藏  举报