给一个 n 行 t 列的矩阵,矩阵第 i 行第 j 列的元素是 i+j。
定义矩阵第 i 行的积为第 i 行所有元素的乘积。
现在要你求矩阵所有行的积的和。答案可能很大,所以 mod 1000000007输出。
100%, 1≤T≤10000 1≤n≤1e10, 1≤t≤1000
也就是求:
你打开了某著名 OJ 准备刷题。
这个 OJ 上一共有 nn 道题,并且你知道你刷第 ii 道题会获得 aiai 的智慧值。对于每道题你都有两种选择:嘴巴切题和老实码完,第 ii 题老实码完需要花费时间 titi,但是嘴巴切它只需要花费 ⌈ti2⌉⌈ti2⌉。一道题不管是嘴巴切还是老实码,都可以获得智慧值,但是你也不想做一个嘴巴选手,所以你允许自己最多嘴巴切 ww 个题。
你算了下自己总共有 SS 的时间,并且你有强迫症,只想从某道题开始顺着往下做,也就是你只想做连续一段的题。问在这 SS 时间内最多可以获得多少智慧值。
用两个set维护即可,S1,S2,S1记录的是直接做的,S2记录的是口胡的,然后用two-pointer维护,然后从S2中选一个最小的,放到S1里面,然后维护就可以了。
在比赛中我是用树状数组+二分维护的,双log,打错了一个-,所以就没有过。
#include
#include
#include
#include
#define lowbit(i) (i&(-i))
using namespace std;
int n,w,s;
int a[200010];
int t[200010];
int p[10010];
int b[10010];
int c[10010];
int temp=10000;
int ans=0;
int nowa=0,nowt;
void add(int x,int tp){
int as;
for(int i=x;i<=temp;i+=lowbit(i)){
p[i]+=tp;
as=temp-x+1;
b[i]+=as*tp;
c[i]+=(as%2==0?as/2:as/2+1)*tp;
}
}
int get_sum(int *now,int t){
int tot=0;
for(int i=t;i>=1;i-=lowbit(i)) tot+=now[i];
return tot;
}
int check(){
int l=1,r=10000,ans=0,mid;
while(l<=r){
mid=(l+r)/2;
if(get_sum(p,mid)>=w){
ans=mid;
r=mid-1;
}
else l=mid+1;
}
return ans;
}
int main(){
scanf("%d %d %d",&n,&w,&s);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) scanf("%d",&t[i]);
int L=1,R=0,we;
while(R<=n){
while(R<=n){
R++;
nowa+=a[R];nowt+=t[R];
we=temp-t[R]+1;add(we,1);
if(R-L+1<=w) we=get_sum(c,temp);
else {
we=check();
we=nowt-get_sum(b,we)+get_sum(c,we)+(get_sum(p,we)-w)*((temp-we+1)/2);
}
if(we>s) break;
else ans=max(ans,nowa);
}
while(L<=R){
nowa-=a[L];nowt-=t[L];
we=temp-t[L]+1;add(we,-1);
if(R-L+1<=w) we=get_sum(c,temp);
else {
we=check();
we=nowt-get_sum(b,we)+get_sum(c,we)+(get_sum(p,we)-w)*((temp-we+1)/2);
}
L++;
if(we<=s) {
ans=max(ans,nowa);
break;
}
}
}
printf("%d",ans);
}
给你一棵 nn 个点的无根树,点的编号是 1−n1−n。叶子指的是一颗有根树没有孩子的结点。一个友善的叶子集合是由一些叶子组成的非空集合,且满足,这些叶子,在某种 dfs 顺序下(即存在一种 dfs 顺序),按 dfs 顺序取出所有叶子,友善的叶子集合里的叶子在这里面是连续的(顺序无所谓)。现在问你,当这棵树的根是 ii 的时候,一共有多少种友善的叶子集合。答案mod 。
考虑对于每棵子树,是选一边,选全部还是不选。很麻烦,直接暴力60