寒假集训day4

T1:致摸鱼两千年后的你

E[k]表示第k年后钱数的期望,E[0]=n

直 接 列 出 转 移 式 直接列出转移式
考 虑 多 一 年 , 我 们 发 现 , E [ k + 1 ] 的 每 种 情 况 的 概 率 是 E [ k ] 每 种 情 况 的 概 率 ∗ 0.5 考虑多一年,我们发现,E[k+1]的每种情况的概率是E[k]每种情况的概率*0.5 E[k+1]E[k]0.5
而 每 种 情 况 之 间 是 存 在 联 系 的 , 即 第 k 年 的 每 种 情 况 , 如 S , 第 k + 1 年 就 存 在 S , S − 1 而每种情况之间是存在联系的,即第k年的每种情况,如S,第k+1年就存在S,S-1 kSk+1SS1
所 以 E [ k + 1 ] = E [ k ] ∗ 2 − 1 2 所以E[k+1]=E[k]*2-\dfrac{1}{2} E[k+1]=E[k]221
最 后 用 必 修 5 的 知 识 推 一 推 , 就 可 以 得 到 2 E [ k ] = 2 ∗ ( 2 k E [ 0 ] − ( 2 k − 1 − 1 ) ) + 1 最后用必修5的知识推一推,就可以得到2E[k]=2*(2^kE[0]-(2^{k-1}-1))+1 52E[k]=2(2kE[0](2k11))+1

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
ll n,k,mod=1e9+7;
ll ksm(ll x,ll pow){
	ll ans=1,res=x%mod;
	while(pow){
		if(pow&1) ans=ans%mod*res%mod;
		res=res*res%mod;
		pow>>=1;
	}
	return ans%mod;
}
int main(){
	scanf("%lld%lld",&n,&k);
	n%=mod;
	if(k==0){
		printf("%lld",(n*2)%mod);
		return 0;
	}
	ll jc=ksm(2,k),jc2=ksm(2,k-1);
	//printf("check jc=%d jc2=%d\n",jc,jc2);
	ll ans=((((2*(jc*(n%mod)%mod)%mod-(2*jc2%mod%mod)+mod)%mod+2)%mod-1)%mod+mod)%mod;
	if(ans<0) ans+=mod;
	printf("%lld",ans);
}

T2:阿爽爱上了阿秦
本 题 我 直 接 考 虑 了 二 维 的 d p , 但 发 现 最 小 值 很 难 维 护 , 所 以 我 用 v e c t o r , 但 是 却 爆 了 本题我直接考虑了二维的dp,但发现最小值很难维护,所以我用vector,但是却爆了 dpvector
其 实 正 解 也 差 不 多 , 多 枚 举 一 维 m n 其实正解也差不多,多枚举一维mn mn
这 题 用 到 了 一 个 经 典 的 d p 优 化 套 路 , 即 要 优 化 时 , 不 要 枚 举 k 这 一 维 , 而 考 虑 k 是 否 有 什 么 特 殊 性 质 , 换 一 种 方 式 枚 举 这题用到了一个经典的dp优化套路,即要优化时,不要枚举k这一维,而考虑k是否有什么特殊性质,换一种方式枚举 dpkk
并 且 可 知 k 是 单 调 的 , 所 以 k 这 一 维 可 以 不 用 枚 举 并且可知k是单调的,所以k这一维可以不用枚举 kk
所 以 最 后 总 的 时 间 复 杂 度 就 是 O ( 最 大 值 n ) 所以最后总的时间复杂度就是O(最大值n) On
注 意 点 : 注意点:
1. 这 题 时 间 卡 得 很 死 , 所 以 不 能 用 m e m s e t , 只 能 在 需 要 的 时 候 赋 初 值 1.这题时间卡得很死,所以不能用memset,只能在需要的时候赋初值 1.memset
2. d p [ i ] [ 0 ] 是 1 , 因 为 没 有 初 值 , 所 以 后 面 需 要 d p [ i ] [ 0 ] 转 移 , 所 以 要 赋 为 1 2.dp[i][0]是1,因为没有初值,所以后面需要dp[i][0]转移,所以要赋为1 2.dp[i][0]1dp[i][0]1

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N=1010;
const ll MOD=998244353;
ll dp[N][N],ans=0,f[N][N];
int n,k,x[N];
int main(){
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++){
		scanf("%d",&x[i]);
	}
	sort(x+1,x+n+1);
	int mx=(x[n]-x[1])/(k-1);
	for(int mn=1;mn<=mx;mn++){
		int c=0;dp[0][0]=1;f[0][0]=1;
		for(int i=1;i<=n;i++)
		   {
		   	dp[i][0]=1;f[i][0]=(f[i-1][0])%MOD;
		while(x[i]-x[c+1]>=mn) c++;
		for(int j=1;j<=min(i,k);j++){
			dp[i][j]=(f[c][j-1]);
			f[i][j]=(f[i-1][j]+dp[i][j])%MOD;
		   }
	    }
	    ans=(ans+f[n][k])%MOD;
	}
	printf("%lld",ans);
}

T3:正反粒子湮灭
看 看 数 据 范 围 , 大 概 可 以 猜 到 用 线 段 树 , 在 仔 细 看 看 , 是 绝 对 值 ? ? ? ! ! ! 果 断 弃 疗 看看数据范围,大概可以猜到用线段树,在仔细看看,是绝对值???!!!果断弃疗 线
我 们 其 实 可 以 枚 举 每 个 属 性 的 正 负 取 值 , 建 2 k 颗 线 段 树 , 再 枚 举 S 和 ( S x o r 2 k − 1 ) , 最 后 统 计 答 案 即 可 我们其实可以枚举每个属性的正负取值,建2^k颗线段树,再枚举S和(Sxor {2^k-1}),最后统计答案即可 2k线S(Sxor2k1,
由 于 我 们 发 现 绝 对 值 如 果 反 过 来 , 那 么 取 值 一 定 没 有 原 值 大 , 所 以 不 合 法 的 方 案 一 定 比 答 案 小 , 所 以 我 们 可 以 直 接 取 最 小 值 由于我们发现绝对值如果反过来,那么取值一定没有原值大,所以不合法的方案一定比答案小,所以我们可以直接取最小值
如 果 取 相 同 的 , 答 案 即 为 0 , 答 案 一 定 大 于 等 于 0 , 所 以 不 会 产 生 矛 盾 如果取相同的,答案即为0,答案一定大于等于0,所以不会产生矛盾 00

需要注意,线段树要开4倍空间

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N=2e5+5;
const ll MAXN=1234567890000;
ll a[N][10];
int n,k,q;
ll ans,treex[N<<2][32],upda[10];
void push_up(int p,int type){
	treex[p][type]=max(treex[p<<1][type],treex[p<<1|1][type]);
}
void make_tree(int l,int r,int p,int type){
	if(l==r){
		int sum=0;
		for(int i=0;i<k;i++){
			if((1<<i)&type){
				sum+=a[l][i];
			}
			else sum-=a[l][i];
		}
		treex[p][type]=sum;
		return;
	}
	int mid=(l+r)>>1;
	make_tree(l,mid,p<<1,type);
	make_tree(mid+1,r,p<<1|1,type);
	push_up(p,type);
}
void uppdate(int l,int r,int p,int id,int num,int type){
	if(l==id&&r==id){
		treex[p][type]=num;
		return;
	}
	int mid=(l+r)>>1;
	if(id<=mid) uppdate(l,mid,p<<1,id,num,type);
	if(id>mid)  uppdate(mid+1,r,p<<1|1,id,num,type);
	push_up(p,type);
}
ll queryx(int l,int r,int p,int fs,int se,int type){
	if(fs<=l&&r<=se){
		return treex[p][type];
	}
	int mid=(l+r)>>1;
	ll mx=-MAXN;
	if(fs<=mid) mx=max(mx,queryx(l,mid,p<<1,fs,se,type));
	if(se>mid)  mx=max(mx,queryx(mid+1,r,p<<1|1,fs,se,type));
	return mx; 
}
int main(){
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++)
	for(int j=0;j<k;j++){
		scanf("%lld",&a[i][j]);
	}
	for(int i=0;i<(1<<k);i++){
		make_tree(1,n,1,i);
	}
	scanf("%d",&q);
	while(q--){
		int tp;
		scanf("%d",&tp);
		if(tp==1){
			int ai;
			scanf("%d",&ai);
			for(int i=0;i<k;i++){
				scanf("%lld",&upda[i]);
			}
			for(int i=0;i<(1<<k);i++){
				int sum=0;
				for(int j=0;j<k;j++){
					if((1<<j)&i) sum+=upda[j];
					else sum-=upda[j];
				}
				uppdate(1,n,1,ai,sum,i);
			}
		}
		if(tp==2){
			int l,r;
			scanf("%d%d",&l,&r);
			ans=0;
			for(int S=0;S<(1<<k);S++)
			{
			int T=S^((1<<k)-1);
			ll ans1=queryx(1,n,1,l,r,S),ans2=queryx(1,n,1,l,r,S^((1<<k)-1));
			ans=max(ans1+ans2,ans);
		    }
			printf("%lld\n",ans); 
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值