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
而每种情况之间是存在联系的,即第k年的每种情况,如S,第k+1年就存在S,S−1
所
以
E
[
k
+
1
]
=
E
[
k
]
∗
2
−
1
2
所以E[k+1]=E[k]*2-\dfrac{1}{2}
所以E[k+1]=E[k]∗2−21
最
后
用
必
修
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
最后用必修5的知识推一推,就可以得到2E[k]=2∗(2kE[0]−(2k−1−1))+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,但是却爆了
本题我直接考虑了二维的dp,但发现最小值很难维护,所以我用vector,但是却爆了
其
实
正
解
也
差
不
多
,
多
枚
举
一
维
m
n
其实正解也差不多,多枚举一维mn
其实正解也差不多,多枚举一维mn
这
题
用
到
了
一
个
经
典
的
d
p
优
化
套
路
,
即
要
优
化
时
,
不
要
枚
举
k
这
一
维
,
而
考
虑
k
是
否
有
什
么
特
殊
性
质
,
换
一
种
方
式
枚
举
这题用到了一个经典的dp优化套路,即要优化时,不要枚举k这一维,而考虑k是否有什么特殊性质,换一种方式枚举
这题用到了一个经典的dp优化套路,即要优化时,不要枚举k这一维,而考虑k是否有什么特殊性质,换一种方式枚举
并
且
可
知
k
是
单
调
的
,
所
以
k
这
一
维
可
以
不
用
枚
举
并且可知k是单调的,所以k这一维可以不用枚举
并且可知k是单调的,所以k这一维可以不用枚举
所
以
最
后
总
的
时
间
复
杂
度
就
是
O
(
最
大
值
n
)
所以最后总的时间复杂度就是O(最大值n)
所以最后总的时间复杂度就是O(最大值n)
注
意
点
:
注意点:
注意点:
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]是1,因为没有初值,所以后面需要dp[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和(Sxor2k−1),最后统计答案即可
由
于
我
们
发
现
绝
对
值
如
果
反
过
来
,
那
么
取
值
一
定
没
有
原
值
大
,
所
以
不
合
法
的
方
案
一
定
比
答
案
小
,
所
以
我
们
可
以
直
接
取
最
小
值
由于我们发现绝对值如果反过来,那么取值一定没有原值大,所以不合法的方案一定比答案小,所以我们可以直接取最小值
由于我们发现绝对值如果反过来,那么取值一定没有原值大,所以不合法的方案一定比答案小,所以我们可以直接取最小值
如
果
取
相
同
的
,
答
案
即
为
0
,
答
案
一
定
大
于
等
于
0
,
所
以
不
会
产
生
矛
盾
如果取相同的,答案即为0,答案一定大于等于0,所以不会产生矛盾
如果取相同的,答案即为0,答案一定大于等于0,所以不会产生矛盾
需要注意,线段树要开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);
}
}
}