2019牛客暑期多校训练营(第七场)E F H I
E Find the median
题意:每次往序列中增加连续的[l,r]的数,每加入一次就询问当前序列的中位数。
解法:此题没有要求在线,那么直接离线+线段树+二分就可以了。求出每个端点之后排序得到数组b,线段树每个叶子结点i存储的是区间[ b[i-1]+1,b[i] ]的系数(即当前序列有多少个[ b[i-1]+1,b[i] ])。修改时顺便维护当前总的数个数sum,然后处理询问就是直接在线段树上二分就可以了。
#include<bits/stdc++.h>
#define lc o*2
#define rc o*2+1
#define LL long long
using namespace std;
const int maxn = 4e5+;
LL sumv[*maxn],addv[*maxn];
int a[maxn],b[maxn];
int l[*maxn],r[*maxn];
int ll[*maxn],rr[*maxn];
int n;
int X1,X2,A1,B1,C1,M1;
int Y1,Y2,A2,B2,C2,M2;
int tot;
void init() {
int X3,Y3;
a[]=min(X1,Y1)+,a[]=min(X2,Y2)+;
b[]=max(X1,Y1)+,b[]=max(X2,Y2)+;
for(int i=; i<=n; i++) {
X3 = ((LL)A1*X2+(LL)B1*X1+C1)%M1;
Y3 = ((LL)A2*Y2+(LL)B2*Y1+C2)%M2;
a[i]=min(X3,Y3)+;
b[i]=max(X3,Y3)+;
X1 = X2;
X2 = X3;
Y1 = Y2;
Y2 = Y3;
}
}
int c[*maxn];
int cnt;
void pushup(int o) {
sumv[o]=sumv[lc]+sumv[rc];
ll[o]=ll[lc];
rr[o]=rr[rc];
}
void pushdown(int o) {
if(addv[o]) {
sumv[lc]+=(rr[lc]-ll[lc]+)*addv[o];
sumv[rc]+=(rr[rc]-ll[rc]+)*addv[o];
addv[lc]+=addv[o];
addv[rc]+=addv[o];
addv[o]=;
}
}
void build(int o,int L,int R){
if(L==R){
ll[o]=l[L];
rr[o]=r[L];
return;
}
int M = (L+R)>>;
build(lc,L,M);
build(rc,M+,R);
pushup(o);
}
void update(int o,int L,int R,int ql,int qr,int v) {
if(ql<=L&&R<=qr) {
sumv[o]+=(LL)(rr[o]-ll[o]+)*v;
addv[o]+=v;
return;
}
pushdown(o);
int M =(L+R)>>;
if(ql<=M)update(lc,L,M,ql,qr,v);
if(qr>M)update(rc,M+,R,ql,qr,v);
pushup(o);
}
int query(int o,int L,int R,LL k){
if(L==R){
LL f = sumv[o]/(rr[o]-ll[o]+);
LL c = (k-)/f;
return (ll[o]+c);
}
pushdown(o);
int M = (L+R)>>;
if(k>sumv[lc])return query(rc,M+,R,k-sumv[lc]);
else return query(lc,L,M,k);
}
int main() {
cin>>n;
cin>>X1>>X2>>A1>>B1>>C1>>M1;
cin>>Y1>>Y2>>A2>>B2>>C2>>M2;
init();
// for(int i=1; i<=n; i++)cin>>a[i]>>b[i];
for(int i=; i<=n; i++) {
c[++cnt]=a[i];
c[++cnt]=b[i];
}
sort(c+,c++cnt);
cnt = unique(c+,c++cnt)-(c+);
for(int i=; i<=cnt; i++) {
l[++tot]=c[i];
r[tot]=c[i];
if(i!=cnt&&c[i+]-c[i]>) {
l[++tot]=c[i]+;
r[tot]=c[i+]-;
}
}
build(,,tot);
LL now = ;
for(int i=; i<=n; i++) {
int L = lower_bound(l+,l++tot,a[i])-l;
int R = lower_bound(r+,r++tot,b[i])-r;
update(,,tot,L,R,);
now += b[i]-a[i]+;
printf("%d\n",query(,,tot,(now+)/));
}
return ;
}
F Energy stones
题意:有n个石头,每个石头有初始能量ei,每秒增长能量li,能量上限ci。有m次收割操作(t,si,ti)代表第t秒收割下标[si,ti]的石头能量,石头的能量被收割之后会变成0然后重新增长。问收割总能量。
解法:这题解法偏思维+数据结构。首先是收割一段下标的石头能量此只有一次询问,那么容易想到差分打标记的办法,对于一个收割(t,si,ti),我们在石头si打t的标记代表收割开始,在ti+1打-t的标记代表收割结束。然后我们石头从左往右扫,就容易得到每个石头的收割开始与结束标记。再进一步观察其实对于每个石头这些开始与结束标记就组成了一段段时间段,我们我们的问题就是怎么维护这些时间段以及计算这些时间段对答案的贡献。
方法是用Set+BIT的方式,用Set来保存时间点,用Bit来保存时间段长度(注意这句话非常重要)。那么每当扫到i点有插入或者删除标记的话,我们先在Set里查找这个时间点的位置,因为Set保存了所有的时间点,所以找到时间点的位置之后我们就能知道插入/删除这个时间点对时间段长度的影响,那么根据这些影响就更新Bit。那么时间段长度就得到实时更新,根据这些时间段我们就能算出该石头对答案的贡献。
一些具体细节:①在set插入/删除时间点有一番细节的操作,以插入为例,要分三种情况:插到set头,插到set尾,插到set中。这三种情况有不同操作要自己细细想。②Bit其实有两个Bit,bit1[i]记录时间段i的数值和,bit2[i]记录时间段i的个数。③怎么计算石头对答案贡献?分两种三种贡献,第一是初始能量,第二是不会增长到上限ci的贡献(就是时间段长度<=ci/li的时间段)这个贡献用Bit1算,第三是增长到了ci的贡献,这个贡献用Bit2算。
有一些东西比较难说情况,建议看代码理解:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=2e5+;
int n,m,e[N],l[N],c[N];
vector<int> h[N];
set<int> s; LL bit1[N],bit2[N]; //bit1[i]记录时间段i的数值和,bit2[i]记录时间段i的个数
void update(int x,int v) {
if (x==) return;
for (;x<N;x+=x&-x) {
bit1[x]+=v;
if (v>) bit2[x]++; else bit2[x]--;
}
}
LL query1(int x) {
LL ret=;
for (;x;x-=x&-x) ret+=bit1[x];
return ret;
}
LL query2(int x) {
LL ret=;
for (;x;x-=x&-x) ret+=bit2[x];
return ret;
} void addtag(int x) { //在set添加时间点并更新bit的时间段信息
if (s.empty()) { s.insert(x); return; }
auto t=s.lower_bound(x);
if (t==s.begin()) {
int tmp=*(s.begin())-x; update(tmp,tmp);
}else if (t==s.end()) {
int tmp=x-*prev(s.end()); update(tmp,tmp);
} else {
int tmp=*t-*prev(t); update(tmp,-tmp);
tmp=*t-x; update(tmp,tmp);
tmp=x-*prev(t); update(tmp,tmp);
}
s.insert(x);
} void deltag(int x) { //在set删除时间点并更新bit的时间段信息
auto t=s.lower_bound(x);
if (s.size()==) { s.erase(t); return; }
if (t==s.begin()) {
int tmp=*next(t)-x; update(tmp,-tmp);
} else if (next(t)==s.end()) {
int tmp=x-*prev(t); update(tmp,-tmp);
} else {
int tmp=x-*prev(t); update(tmp,-tmp);
tmp=*next(t)-x; update(tmp,-tmp);
tmp=*next(t)-*prev(t); update(tmp,tmp);
}
s.erase(t);
} int main()
{
int T,cas=; cin>>T;
while (T--) {
cin>>n;
for (int i=;i<=n;i++) scanf("%d%d%d",&e[i],&l[i],&c[i]);
cin>>m;
for (int i=;i<=n+;i++) h[i].clear();
for (int i=;i<=m;i++) {
int t,si,ti; scanf("%d%d%d",&t,&si,&ti);
h[si].push_back(t); h[ti+].push_back(-t); //打标记
} LL ans=;
for (int i=;i<=n+;i++) {
for (int j=;j<h[i].size();j++) {
int t=h[i][j]; //取出标记
if (t>) addtag(t); else deltag(-t);
}
if (s.empty()) continue;
ans+=min((LL)c[i],e[i]+(LL)*(s.begin())*l[i]); //特殊处理初始能量
if (l[i]==) continue;
int d=c[i]/l[i]; //最多充能天数
ans+=(LL)query1(d)*l[i]+(LL)(query2(N-)-query2(d))*c[i]; //用BIT计算贡献
}
printf("Case #%d: %lld\n",++cas,ans);
}
return ;
}
H Pair
题意:给出A,B,C;问存在多少数字对<x,y> 满足 x€[1,A],y€[1,B],x&y>C||x^y<C 。
解法:这题是真的不会做,比赛的时候一直在想FFT什么的完全想偏了qwq。解法参考https://blog.csdn.net/qq_41117236/article/details/98884028这位大佬的。
首先要想到是一道数位dp的题目,然后设计出正确的dp状态:dp[i][c1][c2][lim1][lim2]代表当前填到第i位(从高位开始填),c1为前i位满足条件一情况,c2为前i位满足条件二情况,且A是否limit,B是否limit。特别要提到的是c1/c2只要3中状态(-1,0,1),-1是代表不满足条件(高位不满足已经凉了低位不用看了),1是已经满足条件(高位满足了低位也无所谓随便填),0是未确定(未确定其实就是还没满足但不是肯定不满足,相当于凉了一般但是还得看后面发挥)。
然后就是数位dp的常规套路,枚举每一位填什么顺便计算方案数。
#include<bits/stdc++.h>
using namespace std;
#define LL long long
LL dp[][][][][],pw[],n1[],n2[];
num1[],num2[],num3[];
LL dfs(int len,int c1,int c2,bool lim1,bool lim2)
{
if(c1==-&&c2==-) return ; //两个条件都不满足
if(len==) return c1==||c2==; //所有位都取到了
if(c1==||c2==){ //任一满足
LL a=pw[len],b=pw[len]; //当前位的大小即最多可以取的不同数字
if(lim1) a=n1[len]+; //若有限制,只能取A取得到的
if(lim2) b=n2[len]+;
return a*b;
}
if(dp[len][c1][c2][lim1][lim2]!=-)
return dp[len][c1][c2][lim1][lim2];
int up1=lim1?num1[len]:,up2=lim2?num2[len]:; //如果有限制就按限制,没有限制就到1
LL res=;
for(int i=;i<=up1;i++) //枚举确定x和y当前位的取值是0还是1
for(int j=;j<=up2;j++){
int x=i&j,y=i^j,nc1=c1,nc2=c2;
if((!c1&&x<num3[len]||c1==-)&&(!c2&&y>num3[len]||c2==-))
continue;
if(!c1){
if(x<num3[len]) nc1=-;
else if(x>num3[len]) nc1=;
else nc1=;
}
if(!c2){
if(y>num3[len]) nc2=-;
else if(y<num3[len]) nc2=;
else nc2=;
}
res+=dfs(len-,nc1,nc2,lim1&&i==up1,lim2&&j==up2); //确定下一位
}
dp[len][c1][c2][lim1][lim2]=res;
return res;
}
LL cal(LL A,LL B,LL C)
{
memset(num1,,sizeof(num1));
memset(num2,,sizeof(num2));
memset(num3,,sizeof(num3));
//取出ABC二进制形式的每一位
int t1=,t2=,t3=;
while(A) num1[++t1]=A&,A>>=;
while(B) num2[++t2]=B&,B>>=;
while(C) num3[++t3]=C&,C>>=;
int t=max(t1,max(t2,t3)); //最高位
for(int i=t;i>;i--){
n1[i]=n2[i]=;
for(int j=i;j>;j--){
n1[i]=n1[i]<<|num1[j]; //n1[i]*2+num1[j],表示A取到第i位的大小
n2[i]=n2[i]<<|num2[j]; //表示B取到第i位的大小即不同数字个数
}
}
return dfs(t,,,,);
}
void init()
{
pw[]=;
for(int i=;i<;i++)
pw[i]=pw[i-]*; //二进制的第i位表示的大小
}
int main()
{
init();
int t; scanf("%d",&t);
while(t--){
memset(dp,-,sizeof(dp)); //初始化
LL A,B,C; scanf("%lld%lld%lld",&A,&B,&C);
printf("%lld\n",cal(A,B,C)-min(A,C-)-min(B,C-)-);
//还需要减去x=0且y!=0,y=0且x!=0,x=0且y=0的部分
}
return ;
}
I Chessboard
题意:给定n,m。求k*k的矩阵,1<=k<=n,矩阵内的每个元素都不小于m,且矩阵内不同行不同列的元素相加都为一个定值T,且T<=n。问这样的矩阵有多少种,MOD998244353
解法:比赛的时候想不到,只能看题解了:https://blog.csdn.net/qq_43383246/article/details/99240320。
要加强组合数学的推理能力(qwq)。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int p=;
LL fac[],inv[];
LL fsp(LL a,int b){
LL res=;
while(b){
if(b&)res*=a,res%=p;
a*=a,a%=p;
b>>=;
}
return res;
}
LL C(int n,int m){
if(m>n||m<)return ;
return fac[n]*inv[n-m]%p*inv[m]%p;
}
int main(){
int T,n,m;scanf("%d",&T);
fac[]=fac[]=1LL;
for(int i=;i<=;i++)fac[i]=fac[i-]*i%p;
inv[]=inv[]=1LL;inv[]=fsp(fac[],p-);
for(int i=;i>=;i--)inv[i-]=inv[i]*i%p;
while(T--){
scanf("%d%d",&n,&m);
LL ans=;
for(int k=;k<=n;k++){
for(int t=;t<=n-k*m;t++){
ans+=C(t+*k-,*k-);
ans%=p;
ans-=C(t+k-,*k-);
ans=(ans+p)%p;
}
}
printf("%lld\n",ans);
}
return ;
}
2019牛客暑期多校训练营(第七场)E F H I的更多相关文章
- 2019牛客暑期多校训练营(第二场)F.Partition problem
链接:https://ac.nowcoder.com/acm/contest/882/F来源:牛客网 Given 2N people, you need to assign each of them ...
- 2019牛客暑期多校训练营(第二场)-F artition problem
题目链接:https://ac.nowcoder.com/acm/contest/882/F 题意:将2×n个人分成两组,每组n个人,求一个组中所有人和另外一组的所有人的竞争值之和. 思路: 比赛时看 ...
- 2019牛客暑期多校训练营(第二场) - F - Partition problem - 枚举
https://ac.nowcoder.com/acm/contest/882/F 潘哥的代码才卡过去了,自己写的都卡不过去,估计跟评测机有关. #include<bits/stdc++.h&g ...
- 2019牛客暑期多校训练营(第九场)A:Power of Fibonacci(斐波拉契幂次和)
题意:求Σfi^m%p. zoj上p是1e9+7,牛客是1e9: 对于这两个,分别有不同的做法. 前者利用公式,公式里面有sqrt(5),我们只需要二次剩余求即可. 后者mod=1e9,5才 ...
- 2019牛客暑期多校训练营(第一场)A题【单调栈】(补题)
链接:https://ac.nowcoder.com/acm/contest/881/A来源:牛客网 题目描述 Two arrays u and v each with m distinct elem ...
- 2019牛客暑期多校训练营(第一场) B Integration (数学)
链接:https://ac.nowcoder.com/acm/contest/881/B 来源:牛客网 Integration 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 5242 ...
- 2019牛客暑期多校训练营(第一场) A Equivalent Prefixes ( st 表 + 二分+分治)
链接:https://ac.nowcoder.com/acm/contest/881/A 来源:牛客网 Equivalent Prefixes 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/ ...
- 2019牛客暑期多校训练营(第一场)A Equivalent Prefixes(单调栈/二分+分治)
链接:https://ac.nowcoder.com/acm/contest/881/A来源:牛客网 Two arrays u and v each with m distinct elements ...
- [状态压缩,折半搜索] 2019牛客暑期多校训练营(第九场)Knapsack Cryptosystem
链接:https://ac.nowcoder.com/acm/contest/889/D来源:牛客网 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 262144K,其他语言52428 ...
- 2019牛客暑期多校训练营(第二场)J-Subarray(思维)
>传送门< 前言 这题我前前后后看了三遍,每次都是把网上相关的博客和通过代码认真看了再思考,然并卵,最后终于第三遍也就是现在终于看懂了,其实懂了之后发现其实没有那么难,但是的的确确需要思维 ...
随机推荐
- CQOI2007 余数之和
Time Limit: 5 Sec Memory Limit: 128 MB Description 给出正整数n和k,计算j(n, k)=k mod 1 + k mod 2 + k mod 3 + ...
- mysql 数据库连接状态查询
查看当前数据库进程 show processlist
- BZOJ3331 BZOJ2013 压力
考前挣扎 圆方树这么早就出现了嘛... 要求每个点必须被经过的次数 所以就是路径上的割点/端点++ 由于圆方树上所有非叶子圆点都是割点 所以就是树上差分就可以辣. 实现的时候出了一点小问题. 就是这里 ...
- 在项目中使用 Maven 私服
#在项目中使用 Maven 私服 在 Maven settings.xml 中添加 Nexus 认证信息(servers 节点下): <server> <id>nexus-re ...
- Linux用户登出之后保持后台进程(nohup)
使用&可以将进程置于后台,但是用户从Shell登出之后,进程会自动结束.想要在登出之后保持进程运行,就要结合nohup命令使用. 例如: nohup find -size +100k > ...
- Web核心之Servlet接口
Servlet(server applet)概念: Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务 ...
- maven插件之maven-surefire-plugin,junit单元测试报告和sonar测试覆盖率的整合说明
POM中配置的如下: <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId> ...
- linux根据进程名获取PID
经常需要Kill多个进程,这些进程包含共同的关键字,可以用一条命令Kill掉它们. ps aux | grep "common" |grep -v grep| cut -c 9-1 ...
- 如何通过Dataphin构建数据中台新增100万用户?
欢迎来到数据中台小讲堂!这一期我们来看看,作为阿里巴巴数据中台(OneData - OneModel.OneID.OneService)方法论的产品载体,Dataphin如何帮助传统零售企业实现数字化 ...
- 知道一个数组某个index对应的值 不知道下标的情况下删除该值
for (index,item) in Arr.enumerated() { if item == item { Arr.remove(at: index) } } 更好的方法是用数组的filter尾 ...