noip模拟47[适合]

noip模拟47 solutions

这套题特别好,我特别喜欢

因为这个非常符合我的水平,第一题能一眼出思路,半个小时内切掉

后面的题如果脑子清醒的话, 很容易就能想出来

T1 Prime

直接线性筛前面的质数,然后倍数筛上面的类素数

AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll long long
const int N=1e7+5;
const int M=1e6+5;
bool vis[N],via[N];
ll l,r,k,ans;
ll pri[M],cnp;
signed main(){
	//cout<<(sizeof(pri)>>20)<<endl;
	scanf("%lld%lld%lld",&l,&r,&k);
	k=min(k,(ll)sqrt(r));
	for(re i=2;i<=k;i++){
		if(!via[i])pri[++cnp]=i;
		for(re j=1;j<=cnp&&pri[j]*i<=k;j++){
			via[pri[j]*i]=true;
			if(i%pri[j]==0)break;
		}
	}
	for(re i=1;i<=cnp;i++){
		//cout<<pri[i]<<endl;
		ll tmp=l/pri[i];
		if(pri[i]*tmp<l)tmp++;
		if(tmp==1)tmp++;
		while(tmp*pri[i]<=r){
			vis[tmp*pri[i]-l]=true;
			tmp++;
		}
	}
	for(ll i=0;i<=r-l;i++)
		if(!vis[i]){
			ans^=(i+l);
			//if(i+l<=10000001030000ll)cout<<i+l<<" ";
		}
	printf("%lld",ans);
}

T2 Sequence

这个有一个转移方程,设dp[i]表示以i结尾的数然后方案有多少

\[dp[i]=1+\sum\limits^{j=1}_{k}dp[j] \]

这个就相当于在每一个后面又接上了一个数,

那么这样的话,无论你转移那一个,得到的数都是一样的

我们为了保证答案最优,我们一定会找一个最小的数来转移

前n个我们可以直接转移,后m个我们就找最小的,不停转移就好了

65pts暴力
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll long long
const ll mod=1e9+7;
ll n,m,k,a,ans;
ll dp[205],sum;
signed main(){
	scanf("%lld%lld%lld",&n,&m,&k);
	for(re i=1;i<=n;i++){
		ll x;scanf("%lld",&x);
		ll tmp=dp[x];
		dp[x]=(sum+1)%mod;
		sum=(sum-tmp+dp[x]+mod)%mod;
	}
	if(m==0){printf("%lld",sum);return 0;}
	for(re i=1;i<=m;i++){
		ll mn=0x3f3f3f3f3f3f,who;
		for(re j=1;j<=k;j++){
			if(mn>dp[j]){mn=dp[j],who=j;}
		}
		ll tmp=dp[who];
		dp[who]=(sum+1)%mod;
		sum=(sum-tmp+dp[who]+mod)%mod;
	}
	for(re i=1;i<=k;i++)ans=(ans+dp[i])%mod;
	printf("%lld",ans);
}

你发现,好像最小的就变成最大的了诶

就相当于,吧最小的拿出来,换成最大的,然后放到最后,不停的做这个操作就行了

那么这个就可以用矩阵优化了

[ dp[1] , dp[2] , dp[3] , 1]

这个是原矩阵的第一行,我们不在乎后面的

按照上面说的,假设我们已经拍好序了,那么只要循环移动就行了

那么矩阵就是

0 0 1 0
1 0 1 0
0 1 1 0
0 0 1 1

以此类推

注意排序的时候不能直接按照dp值排序,因为取模了

你发现出现位置越早的肯定值越小,然后就按照位置排序就行了

AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll long long
const ll mod=1e9+7;
ll n,m,k,a,ans;
ll sum;
struct node{
	ll d,p;
	node(){};
	bool operator < (node a)const{
		return p<a.p;
	}
}sca[105];
struct matrix{
	ll x[105][105];
	matrix(){}
	matrix operator * (matrix b)const{
		matrix c;
		for(re i=1;i<=k+1;i++)
			for(re j=1;j<=k+1;j++){
				c.x[i][j]=0;
				for(re l=1;l<=k+1;l++)
					c.x[i][j]=(c.x[i][j]+x[i][l]*b.x[l][j]%mod);
				c.x[i][j]%=mod;
			}
		return c;
	}
}dp;
matrix ksm(matrix a,ll y){
	matrix ret;memset(ret.x,0,sizeof(ret.x));
	for(re i=1;i<=k+1;i++)ret.x[i][i]=1;
	while(y){
		if(y&1)ret=ret*a;
		a=a*a;y>>=1;
	}
	return ret;
}
signed main(){
	scanf("%lld%lld%lld",&n,&m,&k);
	for(re i=1;i<=n;i++){
		ll x;scanf("%lld",&x);
		ll tmp=sca[x].d;
		sca[x].d=(sum+1)%mod;
		sum=(sum-tmp+sca[x].d+mod)%mod;
		sca[x].p=i;
	}
	sort(sca+1,sca+k+1);
	for(re i=1;i<=k;i++)dp.x[1][i]=sca[i].d;
	dp.x[1][k+1]=1;
	matrix xs;memset(xs.x,0,sizeof(xs.x));
	for(re i=1;i<=k-1;i++)xs.x[i+1][i]=1;
	for(re i=1;i<=k+1;i++)xs.x[i][k]=1;
	xs.x[k+1][k+1]=1;
	dp=dp*ksm(xs,m);
	for(re i=1;i<=k;i++)ans=(ans+dp.x[1][i])%mod;
	printf("%lld",ans);
}

T3 Omeed

这个又是一个期望题,我真的不会,但是发现我自己很傻缺

连最简单的期望式子都不会推,我不在这里写了,太丢人了,直接看官方题解吧

至于如何用线段树

把题解式子化简一下,\((t-(t-1)*p_i)f_{i-1}+pi\),最后都能化简成为l-1的表达式

那么\(f_{l-1}\)为0,没有啥用,我们只需要后面的,

\(\varphi _i\)表示\((t-(t-1)*p_i)\),那么我们的\(f_n=\sum\limits^{n}_{i=1}\prod\limits^{n}_{j=i+1}\varphi_jp_i\)

这个很直观吧

\[ans=\sum\limits^{n}_{i}f_{i-1}*p_i \]

然后用线段树维护这个就好了,如果你要不明白请到机房找我,因为式子太多了

我没有时间写了,

大概就是你维护两个区间,合并的时候,计算左区间的右端点的f,对又区间的贡献就好了

只需要维护区间的右端点和这个贡献的系数

AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll int
const int N=5e5+5;
const ll mod=998244353;
ll n,q,ta,tb,t,A,B,ans;
ll p[N];
inline int o()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch>'9'||ch<'0')
	{
		if(ch=='-')	f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*f;
}
inline ll ksm(ll x,ll y){
	ll ret=1;
	while(y){
		if(y&1)ret=1ll*ret*x%mod;
		x=1ll*x*x%mod;y>>=1;
	}
	return ret;
}
struct XDS{
	#define ls x<<1
	#define rs x<<1|1
	ll fa[N*4],fr[N*4],phi[N*4],sum[N*4],siz[N*4],fb[N*4];
	struct RET{
		ll rfa,rfr,rsu;
		RET(){}
		RET(int z,int w,int u){
			rfa=z;rfr=w;rsu=u;
		}
	}ret;
	void pushup(int x){
		fa[x]=(1ll*fa[ls]+1ll*fa[rs])%mod;
		fb[x]=(1ll*fb[ls]+1ll*fb[rs]*phi[ls])%mod;
		phi[x]=1ll*phi[ls]*phi[rs]%mod;
		fr[x]=(1ll*fr[rs]+1ll*fr[ls]*phi[rs]%mod)%mod;
		sum[x]=(1ll*sum[rs]+1ll*sum[ls]+1ll*fr[ls]*fb[rs]%mod)%mod;
		//cout<<fr[ls]<<" "<<fb[rs]<<endl;
		return ;
	}
	void build(int x,int l,int r){
		if(l==r){
			fa[x]=fr[x]=p[l];
			phi[x]=(1ll*t-1ll*(t-1)*p[l]%mod+mod)%mod;
			sum[x]=0;fb[x]=fa[x];
			return ;
		}
		int mid=l+r>>1;
		build(ls,l,mid);
		build(rs,mid+1,r);
		pushup(x);return ;
	}
	void ins(int x,int l,int r,int pos,ll v){
		siz[x]=r-l+1;
		if(l==r){
			fa[x]=fr[x]=v;
			phi[x]=(1ll*t-1ll*(t-1)*v%mod+mod)%mod;
			sum[x]=0;fb[x]=fa[x];
			//cout<<l<<" "<<fa[x]<<" "<<fb[x]<<endl;
			return ;
		}
		int mid=l+r>>1;
		if(pos<=mid)ins(ls,l,mid,pos,v);
		else ins(rs,mid+1,r,pos,v);
		pushup(x);return ;
	}
	void query(int x,int l,int r,int ql,int qr){
		if(ql<=l&&r<=qr){
			//cout<<l<<" "<<r<<" "<<sum[x]<<endl;
			ret.rfa=(1ll*ret.rfa+fa[x])%mod;
			ret.rsu=(1ll*ret.rsu+1ll*sum[x]+1ll*ret.rfr*fb[x]%mod)%mod;
			ret.rfr=(1ll*ret.rfr*phi[x]+1ll*fr[x])%mod;
			return ;
		}
		int mid=l+r>>1;
		if(ql<=mid)query(ls,l,mid,ql,qr);
		if(qr>mid)query(rs,mid+1,r,ql,qr);
		return ;
	}
	#undef ls
	#undef rs
}xds;
signed main(){
	int nmb;scanf("%d",&nmb);
	//scanf("%d%d%d%d%d%d",&n,&q,&ta,&tb,&A,&B);
	n=o();q=o();ta=o();tb=o();A=o();B=o();
	t=1ll*ta*ksm(tb,mod-2)%mod;
	//cout<<t<<endl;
	for(re i=1;i<=n;i++){
		ll wa,wb;//scanf("%d%d",&wa,&wb);
		wa=o();wb=o();
		p[i]=1ll*wa*ksm(wb,mod-2)%mod;
	}
	xds.build(1,1,n);
	//cout<<((t-(t-1)*p[2]%mod+mod)*p[1]+p[2])%mod<<endl;
	while(q--){
		int typ;//scanf("%d",&typ);//cout<<((p[1]+1)*p[2]%mod+p[1])%mod<<" "<<p[1]<<" "<<p[2]<<endl;
		typ=o();
		if(typ){
			/*memset(f,0,sizeof(f));
			ll sum1=0,sum2=0;*/
			ll l,r;//scanf("%d%d",&l,&r);
			l=o();r=o();
			/*for(re i=l;i<=r;i++){
				f[i]=((f[i-1]+1)*p[i]+(1ll+mod-p[i])*f[i-1]%mod*t)%mod;
				sum2=(sum2+(f[i-1]+1)*p[i])%mod;
				sum1=(sum1+p[i])%mod;
			}*/
			//cout<<f[1]<<endl;
			//cout<<sum1<<" "<<sum2<<" "<<(sum1*A+sum2*B)%mod<<endl;
			xds.ret=XDS::RET(0,0,0);
			//cout<<xds.ret.rfr<<endl;
			xds.query(1,1,n,l,r);
			//cout<<xds.ret.rfa<<" "<<(xds.ret.rsu+xds.ret.rfa)%mod<<endl;
			printf("%lld\n",(1ll*xds.ret.rfa*A%mod+1ll*(1ll*xds.ret.rsu+1ll*xds.ret.rfa)*B%mod)%mod);
		}
		else{
			int x;ll wa,wb;//scanf("%d%d%d",&x,&wa,&wb);
			x=o();wa=o();wb=o();
			p[x]=1ll*wa*ksm(wb,mod-2)%mod;
			xds.ins(1,1,n,x,p[x]);
		}
	}
}

我本来是不写快读的,可是卡常极其严重

posted @ 2021-08-25 08:14  fengwu2005  阅读(55)  评论(0)    收藏  举报