CSP-S 模拟

T1 盘王节

这是一道模拟题,那些细节问题一定要想清楚再写

那么有两种策略:

因为打了御符又不打完肯定不优。

注意一个坑点,就是御符打完之后,可能对方会有负的兵符,这时打负的兵符是比直接打要优的。

双指针做到 O ( n ) O(n) O(n)。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
namespace IO{const int Rlen=1<<22|1;char buf[Rlen],*p1,*p2;inline char gc(){return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;}template<typename T>inline T Read(){char c=gc();T x=0,f=1;while(!isdigit(c))  f^=(c=='-'),c=gc();while( isdigit(c))  x=(x+(x<<2)<<1)+(c^48),c=gc();return f?x:-x;}inline int in()  {return Read<int>();}
}
using IO::in;
const int N=1e6+5;
int n,m1,m2;
struct node{int val,num;bool operator<(const node &p)const{return val<p.val;}
}p1[N],p2[N],p3[N],g1[N],g2[N];
ll defense(){memcpy(g1,p1,sizeof(p1));memcpy(g2,p2,sizeof(p2));for(int i=1,p=1;i<=m1;++i){while(g2[i].num>0){while(p<=n&&g1[p].val<g2[i].val)  ++p;if(p>n&&g2[m1].num>0)  return 0;if(g1[p].num>g2[i].num)  g1[p].num-=g2[i].num,g2[i].num=0;else  g2[i].num-=g1[p].num,g1[p].num=0,++p;}}ll sum=0,ans=0;for(int i=1;i<=n;++i)  if(g1[i].val>0)  ans+=(ll)g1[i].num*g1[i].val,sum+=g1[i].num;for(int i=1;i<=m2;++i){if(p3[i].val>=0)  break;if(sum>=p3[i].num)  ans-=(ll)p3[i].num*p3[i].val,sum-=p3[i].num;else  {ans-=(ll)p3[i].val*sum;break;}}return ans;
}
ll attack(){memcpy(g1,p1,sizeof(p1));memcpy(g2,p3,sizeof(p3));reverse(g1+1,g1+n+1);ll ans=0;for(int i=1,p=1;i<=n;++i){while(g1[i].num>0&&p<=m2&&g1[i].val>g2[p].val){int now=g1[i].val-g2[p].val;if(g1[i].num>g2[p].num)  ans+=(ll)now*g2[p].num,g1[i].num-=g2[p].num,++p;else  ans+=(ll)now*g1[i].num,g2[p].num-=g1[i].num,g1[i].num=0;}if(g1[i].val<=g2[p].val)  return ans;}return ans;
}
int main(){n=in(),m1=in(),m2=in();for(int i=1;i<=n;++i)  p1[i].val=in(),p1[i].num=in();for(int i=1;i<=m1;++i)  p2[i].val=in(),p2[i].num=in();for(int i=1;i<=m2;++i)  p3[i].val=in(),p3[i].num=in();sort(p1+1,p1+n+1),sort(p2+1,p2+m1+1),sort(p3+1,p3+m2+1);printf("%lld\n",max(defense(),attack()));return 0;
}

T2 祝著节

首先有一个结论,就是答案的方案与任意一种 MST 方案,最多只有一条边的差别。

由于 MST 不是最优方案,那么 MST 所有边都是同一个颜色。而当前方案中有差别的两条边中,至少有一条是和 MST 所染颜色不同的,那么在 MST 上强制加上这条边肯定是比当前方案优。

那么我们考虑在 MST 的基础上来算答案。

设 MST 的答案是 s u m sum sum,简单讨论一下:

1 1 1、 s u m > X sum>X sum>X:无解
2 2 2、 s u m = X sum=X sum=X:

枚举不在 MST 上的非树边,算一下强制他们在 MST 上的答案(即在 MST 上加上这条边,再删掉环上最大边)。

记有 p r o b prob prob 条边的答案 = X = X =X。

那么,这 p r o b prob prob 条边(以及最小生成树上的 ( n − 1 ) (n-1) (n−1) 条边)中,应该至少有一条边的颜色与其他边不同。

这不太好算,不如倒着考虑:我们用总方案数减去这些边都染相同颜色的方案数

2 m − 2 × 2 m − ( n − 1 ) − p r o b 2^m-2\times 2^{m-(n-1)-prob} 2m−2×2m−(n−1)−prob

后面有个 × 2 \times 2 ×2 是这些边有两种颜色可以染。

3 3 3、 s u m < X sum<X sum<X:

与上一种情况是类似的,记有 p r o b prob prob 条边的答案 = X = X =X,有 b a n ban ban 条边的答案 < X < X <X。

那么,MST 上的 ( n − 1 ) (n-1) (n−1) 条边以及这 b a n ban ban 条边是必须染成同一个颜色的,不然最优合法方案就 < X <X <X 了。

这个时候的总方案数是 2 × 2 m − ( n − 1 ) − b a n 2\times 2^{m-(n-1)-ban} 2×2m−(n−1)−ban,相当于给这 ( n − 1 ) + b a n (n-1)+ban (n−1)+ban 条边强制染成同色,其他任意染色。

然后还是一样的, p r o b prob prob 里面至少有一条染的色是不一样的,因此方案数就是:

2 ( 2 m − ( n − 1 ) − b a n − 2 m − ( n − 1 ) − b a n − p r o b ) 2(2^{m-(n-1)-ban}-2^{m-(n-1)-ban-prob}) 2(2m−(n−1)−ban−2m−(n−1)−ban−prob)

时间复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
namespace IO{const int Rlen=1<<22|1;char buf[Rlen],*p1,*p2;inline char gc(){return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;}template<typename T>inline T Read(){char c=gc();T x=0,f=1;while(!isdigit(c))  f^=(c=='-'),c=gc();while( isdigit(c))  x=((x+(x<<2))<<1)+(c^48),c=gc();return f?x:-x;}inline int gi()  {return Read<int>();}inline ll  gl()  {return Read<ll >();}
}
using IO::gi;
using IO::gl;
const int N=2e5+5,P=1e9+7;
int add(int x,int y)  {return x+y>=P?x+y-P:x+y;}
int dec(int x,int y)  {return x-y< 0?x-y+P:x-y;}
int mul(int x,int y)  {return 1ll*x*y>=P?1ll*x*y%P:x*y;}
int power(int a,int b){int ans=1;for(;b;b>>=1,a=mul(a,a))  if(b&1)  ans=mul(ans,a);return ans;
}
int n,m,tot,father[N];
struct edges{int u,v,w;}e[N],E[N];
bool operator<(const edges &p,const edges &q)  {return p.w<q.w;}
int find(int x)  {return (father[x]==x)?x:father[x]=find(father[x]);}
int t,first[N],v[N<<1],w[N<<1],nxt[N<<1];
void edge(int x,int y,int z)  {nxt[++t]=first[x],first[x]=t,v[t]=y,w[t]=z;}
void Clear()  {t=0,tot=0;memset(first,0,sizeof(first));}
ll Kruskal(ll sum=0){sort(e+1,e+m+1);for(int i=1;i<=n;++i)  father[i]=i;for(int i=1;i<=m;++i){int u=find(e[i].u),v=find(e[i].v);if(u!=v)  sum+=e[i].w,father[u]=v,edge(e[i].u,e[i].v,e[i].w),edge(e[i].v,e[i].u,e[i].w);else  E[++tot]=e[i];}return sum;
}
int dep[N],fa[N][18],mx[N][18];
void dfs(int x){for(int i=1;i<18;++i){fa[x][i]=fa[fa[x][i-1]][i-1];mx[x][i]=max(mx[x][i-1],mx[fa[x][i-1]][i-1]);}for(int i=first[x];i;i=nxt[i]){int to=v[i];if(to==fa[x][0])  continue;dep[to]=dep[x]+1,fa[to][0]=x,mx[to][0]=w[i];dfs(to);}
}
int LCA(int x,int y){int ans=0;if(dep[x]<dep[y])  swap(x,y);for(int i=17;~i;--i)  if(dep[fa[x][i]]>=dep[y])  ans=max(ans,mx[x][i]),x=fa[x][i];if(x==y)  return ans;for(int i=17;~i;--i)  if(fa[x][i]!=fa[y][i])  ans=max(ans,max(mx[x][i],mx[y][i])),x=fa[x][i],y=fa[y][i];return max(ans,max(mx[x][0],mx[y][0]));
}
ll X;
int main(){int T=gi();while(T--){Clear(),n=gi(),m=gi(),X=gl();for(int i=1;i<=m;++i)  e[i].u=gi(),e[i].v=gi(),e[i].w=gi();ll sum=Kruskal();if(sum>X)  {puts("0");continue;}dep[1]=1,dfs(1);int prob=0;for(int i=1;i<=tot;++i){int u=E[i].u,v=E[i].v;ll now=sum-LCA(u,v)+E[i].w;if(now==X)  prob++;}if(sum==X)  printf("%d\n",dec(power(2,m),power(2,m-n-prob+2)));else{int ban=0;for(int i=1;i<=tot;++i){int u=E[i].u,v=E[i].v;ll now=sum-LCA(u,v)+E[i].w;if(now<X)  ban++;}printf("%d\n",dec(power(2,m-n-ban+2),power(2,m-n-ban-prob+2)));}}return 0;
}

T3 耍望节

不难看出来这是一道数位 d p dp dp。设 f [ i ] [ j ] f[i][j] f[i][j] 表示前 i − 1 i - 1 i−1 位已经确定,且匹配了 m m m 的一个长度为 j j j 的前缀时,第 i i i 位到第 n n n 位有多少种合法的填数方案。

可以处理出 t r a n s [ i ] [ j ] trans[i][j] trans[i][j] 表示在匹配了 m m m 长度为 i i i 的前缀的基础上,加上字符 j j j 能匹配的长度。然后倒着 d p dp dp 求 f f f。

对于询问,首先第一个想法是用试填法来确定 S S S 每一位的值,但是单次询问是 O ( n ) O(n) O(n) 的,需要优化。

那么一个优化思路就是按照重儿子建树,然后倍增优化(2019/10/26 T3 找宝藏 用了一样的套路)。

如果状态 v v v 由状态 u u u 转移而来,我们称 u u u 为 v v v 的后继。

类似树的重链剖分,对于每个状态,我们取其所有后继中 f f f 值最大的一个作为重后继(有多个取字典序最小的),倍增求出每个状态沿着重后继走 2 k 2^k 2k 步之后到达的状态的一些信息,以及这两个状态之间的相对排名

注意由于 k k k 最大是 1 0 18 10^{18} 1018,所以 rank 超过 1 0 18 10^{18} 1018 的部分赋成 1 0 18 + 1 10^{18}+1 1018+1 即可。

此外,倍增优化只是为了降低复杂度的一个优化,不用去过于纠结它的含义。

时间复杂度 O ( n m log ⁡ n + q log ⁡ k log ⁡ n ) O(nm\log n + q\log k\log n) O(nmlogn+qlogklogn)。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
namespace IO{template<typename T>inline T Read(){char c=getchar();T x=0,f=1;while(!isdigit(c))  f^=(c=='-'),c=getchar();while( isdigit(c))  x=((x+(x<<2))<<1)+(c^48),c=getchar();return f?x:-x;}inline int gi()  {return Read<int>();}inline ll  gl()  {return Read<ll >();}
}
using IO::gi;
using IO::gl;
const int N=5e4+5,M=25,P=1e9+7;
const ll inf=1e18+1;
int n,m,q;
int nxt[M],trans[M][10],Pow[18],End[18][N][M],num[18][N][M];
char T[M],S[N];
int add(int x,int y)  {return x+y>=P?x+y-P:x+y;}
int dec(int x,int y)  {return x-y< 0?x-y+P:x-y;}
int mul(int x,int y)  {return 1ll*x*y>=P?1ll*x*y%P:x*y;}
ll fix(ll x)  {return x<inf?x:inf;}
//trans[i][j]表示在已经能匹配i位的情况下,加上j后能匹配的长度。
void init(){nxt[0]=nxt[1]=0;for(int i=2,j=0;i<=m;++i){while(j&&T[i]!=T[j+1])  j=nxt[j];j+=(T[i]==T[j+1]),nxt[i]=j;}for(int i=0;i<m;++i){for(int j=0;j<=9;++j){int k=i;while(k&&j+'0'!=T[k+1])  k=nxt[k];k+=(j+'0'==T[k+1]),trans[i][j]=k;}}for(int i=0;i<=9;++i)  trans[m][i]=m;
}
bool p[N][10];
ll f[N][M],L[18][N][M],R[18][N][M];
//f[i][j]表示前i-1位已经确定,并且匹配了m的一个长度为j的前缀时,第i位到第n位有多少种合法的填数方案。
//L,R,End,num数组都是倍增用的数组。其中L和R表示rank的范围,是(L,R]的一个范围,End表示当前点沿重链跳2^k步后能匹配到哪,num表示当前点沿重链跳2^k步后的数。
void solve_dp(){for(int i=0;i<=m;++i)  f[n+1][i]=(i==m);for(int i=n;i;--i){for(int j=0;j<=m;++j){f[i][j]=0;int pos=-1;ll mx=-1;for(int k=0;k<=9;++k)if(p[i][k]){f[i][j]=fix(f[i][j]+f[i+1][trans[j][k]]);if(f[i+1][trans[j][k]]>mx)  pos=k,mx=f[i+1][trans[j][k]];}End[0][i][j]=trans[j][pos];num[0][i][j]=pos,L[0][i][j]=0;for(int k=0;k<pos;++k)if(p[i][k])  L[0][i][j]=fix(L[0][i][j]+f[i+1][trans[j][k]]);R[0][i][j]=fix(L[0][i][j]+f[i+1][trans[j][pos]]);}}for(int k=1;k<17;++k){int len=(1<<(k-1));for(int i=1;i+(1<<k)<=n+1;++i){for(int j=0;j<=m;++j){int pos=End[k-1][i][j];End[k][i][j]=End[k-1][i+len][pos];num[k][i][j]=add(mul(num[k-1][i][j],Pow[k-1]),num[k-1][i+len][pos]);L[k][i][j]=fix(L[k-1][i][j]+L[k-1][i+len][pos]);R[k][i][j]=fix(L[k-1][i][j]+R[k-1][i+len][pos]);}}}
}
int Query(ll k){if(k>f[1][0])  return -1;int x=1,y=0,ans=0;while(x<=n){for(int i=16;~i;--i){if(x+(1<<i)<=n+1&&L[i][x][y]<k&&R[i][x][y]>=k){     //如果满足重链的条件,就暴力跳重链。 ans=add(mul(ans,Pow[i]),num[i][x][y]);k-=L[i][x][y],y=End[i][x][y],x+=(1<<i);}}if(x>n)  break;for(int i=0;i<=9;++i){    //否则就试填法跳轻链。 if(k>f[x+1][trans[y][i]])  k-=f[x+1][trans[y][i]];else{ans=add(mul(10,ans),i),++x,y=trans[y][i];break;}}}return ans;
}
//Pow在倍增的时候用,记的是10^(2^i),想一想倍增的过程应该能明白。
int main(){Pow[0]=10;for(int i=1;i<17;++i)  Pow[i]=mul(Pow[i-1],Pow[i-1]);int Case=gi();while(Case--){n=gi(),q=gi();scanf("%s%s",T+1,S+1);m=strlen(T+1);for(int i=1;i<=n;++i){if(S[i]=='?')  memset(p[i],true,sizeof(p[i]));else  memset(p[i],false,sizeof(p[i])),p[i][S[i]-'0']=1;}init(),solve_dp();while(q--){ll k=gl();printf("%d\n",Query(k));}}return 0;
}

NOI 模拟

T2 黑白划分

感觉是道比较好的题。

首先考虑怎么算答案,先给出式子:

a n s = ∑ i = 0 n ( 2 n − i × 2 n − i − 4 f ( i ) ) ans=\sum_{i=0}^n\left(2^{n-i}\times2^{n-i}-4f(i)\right) ans=i=0∑n​(2n−i×2n−i−4f(i))

其中 f ( i ) f(i) f(i) 表示以 2 i 2^i 2i 为边长的纯色块的个数, f ( 0 ) = 0 f(0)=0 f(0)=0。

意思就是,枚举正方形边长 2 i 2^i 2i,以 2 i 2^i 2i 为边长的正方形总数是 2 n − i × 2 n − i 2^{n-i}\times2^{n-i} 2n−i×2n−i。减去 4 f ( i ) 4f(i) 4f(i) 是因为,在题目要求在计算时遇到纯色块应该停止,那么我们要减去继续分裂的那部分贡献。

那怎么算 f ( i ) f(i) f(i) 呢。考虑对行和列都分别建一颗线段树,从行中选出颜色相同的段的数量,列做同样处理,乘一乘就是答案。

那么可以用 1 1 1 表示黑色, 0 0 0 表示白色,如果区间和 = 0 =0 =0 或 = r − l + 1 =r-l+1 =r−l+1,就是一个合法的段,就可以加进 f f f 中。

时间复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)。

感觉还是有点口胡,可能还是有点不理解。。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
namespace IO{const int Rlen=1<<22|1;char buf[Rlen],*p1,*p2;inline char gc(){return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;}template<typename T>inline T Read(){char c=gc();T x=0,f=1;while(!isdigit(c))  f^=(c=='-'),c=gc();while( isdigit(c))  x=((x+(x<<2))<<1)+(c^48),c=gc();return f?x:-x;}inline int in()  {return Read<int>();}
}
using IO::in;
const int N=25,M=(1<<20)+5;
int n,q,Log[M];
struct SGT{int cnt[N],sum[M<<2];#define mid ((l+r)>>1)void build(int root,int l,int r){++cnt[Log[r-l+1]];if(l==r)  return;build(root<<1,l,mid),build(root<<1|1,mid+1,r);}void Modify(int root,int l,int r,int pos){if(l==r)  {sum[root]^=1;return;}if(pos<=mid)  Modify(root<<1,l,mid,pos);else  Modify(root<<1|1,mid+1,r,pos);int pre=sum[root];sum[root]=sum[root<<1]+sum[root<<1|1];if((pre==0&&sum[root]!=0)||(pre==r-l+1&&sum[root]!=r-l+1))  cnt[Log[r-l+1]]--;if((pre!=0&&sum[root]==0)||(pre!=r-l+1&&sum[root]==r-l+1))  cnt[Log[r-l+1]]++;}#undef mid
}T[2];
int main(){n=in(),q=in();for(int i=0;i<=n;++i)  Log[1<<i]=i;T[0].build(1,1,(1<<n));T[1].build(1,1,(1<<n));while(q--){int op=in(),x=in();T[op].Modify(1,1,(1<<n),x);ll ans=0;for(int i=0;i<=n;++i){ans+=1ll<<((n-i)*2);if(i)  ans-=4ll*T[0].cnt[i]*T[1].cnt[i];}printf("%lld\n",ans);}return 0;
}

2019/11/05 校内模拟相关推荐

  1. Ubuntu18开机速度突然变慢问题的解决(2019.11.05)

    Ubuntu18开机速度突然变慢问题的解决(2019.11.05) 1 前言(伏笔) 2 分析一:可能是由于一些开机启动程序导致的 3 分析二:从启动日志查找原因 参考 1 前言(伏笔) 笔者的笔记本 ...

  2. linux 开机速度 固态,Ubuntu18开机速度突然变慢问题的解决(2019.11.05)

    Ubuntu18开机速度突然变慢问题的解决(2019.11.05) 1 前言(伏笔) 2 分析一:可能是由于一些开机启动程序导致的 3 分析二:从启动日志查找原因 参考 1 前言(伏笔) 笔者的笔记本 ...

  3. 2018.11.05 NOIP模拟 规避(最短路计数)

    传送门 正难则反. 考虑计算两人相遇的方案数. 先正反跑一遍最短路计数. 然后对于一条在最短路上的边(u,v)(u,v)(u,v),如果(dis(s,u)*2<total&&di ...

  4. 【】每日360题,2019.11.05日21点财会类考试习题答案

    (操作员:刘主管:账套:101账套:操作日期:2015年1月31日)设置固定资产类别.固定资产类别编码:1固定 点我找答案 早9点到晚9点,每小时分享一套试题,每套精选30道题,一同学习! 打开现成E ...

  5. 【每日早报】2019/11/05

    ✦ 阿里巴巴发起成立数字海南有限公司,持股49%为最大股东 ✦ 瑞幸咖啡推出瑞幸坚果,首批上线榴莲.芥末等5种口味腰果 ✦ 蔚来官方二手车正式上线,可享受免费安装家充桩.免费换电等权益 ✦ 三星电子回 ...

  6. 2017.6.11 校内模拟赛

    题面及数据及std(有本人的也有原来的) :2017.6.11 校内模拟赛 T1 自己在纸上模拟一下后就会发现 可以用栈来搞一搞事情 受了上次zsq 讲的双栈排序的启发.. 具体就是将原盘子大小cop ...

  7. 2021年 第十二届蓝桥杯第二期校内模拟赛题解(Java版)

    时隔多日,终于会写一些简单DP了哈哈哈! 稍微改版,方便阅读,若有错,请指出 2019年 第十届蓝桥杯省赛题解(JavaB组版) 2020年 第十一届蓝桥杯第一场省赛题解(JavaB组版) 2020年 ...

  8. 【蓝桥】第十一届软件类校内模拟赛(二)填空题部分

    起晚了起晚了,比赛都快结束了才整完qwq 文章目录 前言 填空题 1题目描述 2题目描述 3题目描述 4题目描述 前言 本题解为第十一届软件类校内模拟赛个人题解,但非官方满分题解,因此,可能存在下列问 ...

  9. [蓝桥杯第十一届校内模拟赛] Apare_xzc

    华中师范大学蓝桥杯第十一届校内模拟赛 2020/3/22 8:00-12:00 题目还是比省赛要简单的,我9:25就做完了. 第一题 分析: 简单题,求给定的1200000的正约数的个数.我们可以暴力 ...

最新文章

  1. jquery的全选,全不选,反选
  2. CNN 中1X1卷积核的作用
  3. NOIP2016 愤怒的小鸟
  4. Eclipse下载及安装hibernate插件
  5. iOS开发复制Label、textView内容是显示拷贝,不是copy
  6. 用计算机绘制三维设计图步骤,3d效果图一般制作步骤
  7. 降低软件复杂性的一般原则和方法
  8. 英语面试:应聘原因篇(转)
  9. Windows Edge浏览器右键菜单透明、难以分辨问题的解决办法
  10. 园友们赶快行动起来,免费获得微软MCSD证书!
  11. 余承东:华为唯一亏损业务是汽车,马斯克推特交易再生变,京东方获iPhone 14订单,今日更多大新闻在此...
  12. 图解MySQL数据库的安插和独霸-2
  13. 51nod3116 松鼠的新家
  14. 软件测试的行业现状,我们的未来在哪里?
  15. 【转载】Cisco 瘦AP回退至胖AP 详细流程
  16. android 暴风影音目录,手机暴风影音缓存文件存储位置在哪 怎么找到手机暴风影音缓存文件...
  17. Java面向对象---面向对象
  18. Python串口通讯发送指令读写NFC源码 支持windows、linux系统
  19. HBuilder常用快捷键
  20. 《留侯论》-苏轼-古代文学

热门文章

  1. 史上最全 Appium 自动化测试从入门到框架实战精华学习笔记(二)
  2. 学计算机系高中该如何选课,滑铁卢大学各专业对于高中选课的要求
  3. G4 ETM: Embedded Trace Macrocell
  4. NazoHell 攻略
  5. 49股权与51股权的区别有哪些
  6. 【wikioi】1041 Car的旅行路线
  7. js删除数组里的某个元素
  8. 2020提供2亿美金,华为与160万开发者、50余家高校共谱鲲鹏故事
  9. 快播活该被抓,跟公诉人是谁无关
  10. Lean的OpenWrt LuCI应用说明