1051E. Vasya and Big Integers

题意

给出三个大整数\(a,l,r\),定义\(a\)的一种合法的拆分为把\(a\)表示成若干个字符串首位相连,且每个字符串的大小在\(l,r\)之间,求每个字符串不能有前导零,求\(a\)有多少种合法的拆分方案。

题解

不难想到\(dp\),设\(dp_i\)表示前\(i\)个数有多少种合法的拆分方案。

\(dp_i=\sum_{j=1}^i dp_{j-1}\)(从\(j+1~i\)拆分的数在\(l,r\)之间)

直接转移是\(O(n^2)\),因为如果新拆分的数的长度小于\(l\)的长度,或者大于\(r\)的长度的话,那肯定是不合法的,所以我们考虑把转移分成三种。

1.新拆分的数的长度等于\(l\)的长度。

2.新拆分的数的长度等于\(r\)的长度。

3.新拆分的数的长度在\([l+1,r-1]\)这个区间里。

对于第三种,随便开个变量xjb维护下就行了。

对于前两种,问题就转换成了比较两个串的字典序。

比较两个字符串字典序的大小,就是相当于比较两个串\(lcp\)的后一位字符的大小。

\(lcp\)?我一眼\(SA\),经机房大佬提醒,突然想到可以写\(hash\)+二分减少代码量其实是太久没写SA忘了SA怎么写了,然后就被卡自然溢出到怀疑人生。

\(cf\)上一定不能写自然溢出!\(cf\)上一定不能写自然溢出!

#include<bits/stdc++.h>
#define For(i,x,y) for (register int i=(x);i<=(y);i++)
#define Dow(i,x,y) for (register int i=(x);i>=(y);i--)
#define cross(i,k) for (register int i=first[k];i;i=last[i])
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
inline ll read(){
ll x=0;int ch=getchar(),f=1;
while (!isdigit(ch)&&(ch!='-')&&(ch!=EOF)) ch=getchar();
if (ch=='-'){f=-1;ch=getchar();}
while (isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
const int N = 1e6+10;
int na,nl,nr;
char a[N],l[N],r[N];
inline void rd(){
scanf("%s%s%s",a+1,l+1,r+1);
na=strlen(a+1),nl=strlen(l+1),nr=strlen(r+1);
}
const ull base = 2333;
const ll mod = 998244353;
ull p[N],hashl[N],hashr[N],hasha[N];
ll P[N],Hashl[N],Hashr[N],Hasha[N];
inline void init(){
p[0]=1;
For(i,1,na) p[i]=p[i-1]*base;
For(i,1,nl) hashl[i]=hashl[i-1]*base+l[i];
For(i,1,nr) hashr[i]=hashr[i-1]*base+r[i];
For(i,1,na) hasha[i]=hasha[i-1]*base+a[i];
P[0]=1;
For(i,1,na) P[i]=P[i-1]*base%mod;
For(i,1,nl) Hashl[i]=(Hashl[i-1]*base+l[i])%mod;
For(i,1,nr) Hashr[i]=(Hashr[i-1]*base+r[i])%mod;
For(i,1,na) Hasha[i]=(Hasha[i-1]*base+a[i])%mod;
}
inline ull Queryl(int x){return hashl[x];}
inline ull queryl(int x){return Hashl[x];}
inline ull Queryr(int x){return hashr[x];}
inline ull queryr(int x){return Hashr[x];}
inline ull Querya(int l,int r){return hasha[r]-hasha[l-1]*p[r-l+1];}
inline ull querya(int l,int r){return (Hasha[r]-Hasha[l-1]*P[r-l+1]%mod+mod)%mod;}
ll sum,dp[N];
inline void Mod(ll &x){for (;x>=mod;x-=mod);}
inline bool checkl(int x){
if (a[x]=='0'&&nl>1) return 0;
int L=1,R=nl,mid,ans=0;
while (L<=R) mid=L+R>>1,(Queryl(mid)==Querya(x,x+mid-1)&&queryl(mid)==querya(x,x+mid-1))?(ans=mid,L=mid+1):R=mid-1;
return (ans==nl)?1:(a[x+ans]>l[ans+1]);
}
inline bool checkr(int x){
if (a[x]=='0'&&nr>1) return 0;
int L=1,R=nr,mid,ans=0;
while (L<=R) mid=L+R>>1,(Queryr(mid)==Querya(x,x+mid-1)&&queryr(mid)==querya(x,x+mid-1))?(ans=mid,L=mid+1):R=mid-1;
return (ans==nr)?1:(a[x+ans]<r[ans+1]);
}
inline void solve(){
dp[0]=1,a[0]='0';
For(i,nl,na){
if (a[i-nl]!='0'&&nr-nl>1) Mod(sum+=dp[i-nl-1]);
if (i-nr+1>0&&a[i-nr+1]!='0'&&nr-nl>1) Mod(sum=sum+mod-dp[i-nr]);
dp[i]=sum;//printf("%d %lld\n",i,sum);
if (nl==nr) Mod(dp[i]+=checkl(i-nl+1)*checkr(i-nr+1)*dp[i-nl]);
else {
Mod(dp[i]+=checkl(i-nl+1)*dp[i-nl]);
if (i-nr+1>0) Mod(dp[i]+=checkr(i-nr+1)*dp[i-nr]);
}
}
printf("%lld",dp[na]);
}
int main(){
rd(),init(),solve();
}

1051F. The Shortest Statement

题意

给出一个无向连通图,给出\(q\)次询问,每次询问\(u->v\)的最短路,边数-点数<=20。

题解

看到联通,边数-点数<=20,一眼想到肯定是把这个图转成几棵树然后求两个在所有树上的距离的\(min\)。

图怎么转成树?还要最短路?\(Dij\)的拓展好像就是一棵树来着。

凭感觉做题.jpg

首先我们先随便搞个点作为起点跑\(Dij\),两个点的最短路如果不是两个点在树上的距离的话,那肯定是就经过了一条非树边,所以我们把所有的非树边都抠出来,然后对非树边的结点为起点,再跑\(Dij\)建树。

最多非树边只会有\(21\)条,所以复杂度\(O(nlogn*21)\)

#include<bits/stdc++.h>
#define For(i,x,y) for (register int i=(x);i<=(y);i++)
#define Dow(i,x,y) for (register int i=(x);i>=(y);i--)
#define cross(i,k) for (register int i=first[k];i;i=last[i])
#define Cross(i,k) for (register int i=First[k];i;i=Last[i])
using namespace std;
typedef long long ll;
inline ll read(){
ll x=0;int ch=getchar(),f=1;
while (!isdigit(ch)&&(ch!='-')&&(ch!=EOF)) ch=getchar();
if (ch=='-'){f=-1;ch=getchar();}
while (isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
const int N = 1e5+10;
int n,m,x,y,z;
int tot,first[N],last[N<<1],to[N<<1];
ll val[N<<1];
inline void Add(int x,int y,int z){to[++tot]=y,val[tot]=z,last[tot]=first[x],first[x]=tot;}
int Tot,First[N],Last[N],To[N];
ll Val[N];
inline void add(int x,int y,int z){To[++Tot]=y,Val[Tot]=z,Last[Tot]=First[x],First[x]=Tot;}
int cnt,rt[50];
bool vis[N];
inline void GetRt(int u,int fa){
vis[u]=1;
cross(i,u){
int v=to[i];
if (v==fa) continue;
if (vis[v]){rt[++cnt]=u;continue;}
}
Cross(i,u) if (To[i]!=fa) GetRt(To[i],u);
}
struct Tree{
int rt;
int size[N],son[N],dep[N],fa[N];
ll dis[N];
inline void dfs(int u){
size[u]=1,dep[u]=dep[fa[u]]+1;
Cross(i,u){
int v=To[i];
if (v==fa[u]) continue;
fa[v]=u,dis[v]=dis[u]+Val[i],dfs(v),size[u]+=size[v];
if (size[v]>size[son[u]]) son[u]=v;
}
}
int top[N];
inline void dfs(int u,int Top){
top[u]=Top;
if (son[u]) dfs(son[u],Top);
Cross(i,u) if (To[i]!=fa[u]&&To[i]!=son[u]) dfs(To[i],To[i]);
}
inline int LCA(int x,int y){
for (;top[x]!=top[y];dep[top[x]]>dep[top[y]]?x=fa[top[x]]:y=fa[top[y]]);
return dep[x]<dep[y]?x:y;
}
inline void Build(){dfs(rt),dfs(rt,rt);}
inline ll Query(int x,int y){return dis[x]+dis[y]-dis[LCA(x,y)]*2;}
}t[50];
struct node{
int u;ll val;
inline bool operator < (const node &b)const{return val>b.val;}
};
priority_queue<node>q;
int fa[N];
ll dis[N],FaVal[N];
inline void Dij(int k,int s){
For(i,1,n) dis[i]=1e18,vis[i]=0;
dis[s]=fa[s]=0,q.push((node){s,0});
while (!q.empty()){
int u=q.top().u;q.pop();
if (vis[u]) continue;vis[u]=1;
cross(i,u){
int v=to[i];
if (dis[u]+val[i]<dis[v]) dis[v]=dis[u]+val[i],q.push((node){v,dis[v]}),fa[v]=u,FaVal[v]=val[i];
}
}
Tot=0,memset(First,0,sizeof First);
//printf("rt=%d ",s);For(i,1,n) printf("%d ",fa[i]);puts("");
For(i,1,n) if (fa[i]) add(fa[i],i,FaVal[i]);
t[k].rt=s,t[k].Build();
}
inline void Build(){For(i,1,cnt) Dij(i,rt[i]);}
int main(){
//freopen("data.in","r",stdin);
//freopen("m.out","w",stdout);
n=read(),m=read();
For(i,1,m) x=read(),y=read(),z=read(),Add(x,y,z),Add(y,x,z);
//puts("");
//rt[cnt=1]=1,GetRt(1,0),Build();
rt[cnt=1],Dij(1,1),memset(vis,0,sizeof vis),GetRt(1,0),Build();
//printf("rt:");For(i,1,cnt) printf("%d ",rt[i]);puts("");
int q=read();
while (q--){
x=read(),y=read();ll ans=1e18;
For(i,1,cnt) ans=min(ans,t[i].Query(x,y));
printf("%lld\n",ans);
}
}
/*
10 10
1 2 9
2 3 5
3 4 5
3 5 8
4 6 6
3 7 6
7 8 8
8 9 4
3 10 4
8 1 7
1
9 5
*/

Codeforces 1051E Vasya and Big Integers&1051F The Shortest Statement的更多相关文章

  1. Codeforces 1051E. Vasya and Big Integers

    题意:给你N个点M条边,M-N<=20,有1e5个询问,询问两点的最短距离.保证没有自环和重边. 题解:连题目都在提示你这个20很有用,所以如果是颗树的话那任意两点的最短距离就是求一下lca搞一 ...

  2. codeforces 1051F The Shortest Statement

    题目链接:codeforces 1051F The Shortest Statement 题意:\(q\)组询问,求任意两点之间的最短路,图满足\(m-n\leq 20\) 分析:一开始看这道题:fl ...

  3. [Codeforces 1051F] The Shortest Statement 解题报告(树+最短路)

    题目链接: https://codeforces.com/contest/1051/problem/F 题目大意: 给出一张$n$个点,$m$条边的带权无向图,多次询问,每次给出$u,v$,要求输出$ ...

  4. Codeforces.1051F.The Shortest Statement(最短路Dijkstra)

    题目链接 先随便建一棵树. 如果两个点(u,v)不经过非树边,它们的dis可以直接算. 如果两个点经过非树边呢?即它们一定要经过该边的两个端点,可以直接用这两个点到 u,v 的最短路更新答案. 所以枚 ...

  5. 2018.09.24 codeforces 1051F. The Shortest Statement(dijkstra+lca)

    传送门 这真是一道一言难尽的题. 首先比赛的时候居然没想出来正解. 其次赛后调试一直调不出来最后发现是depth传错了. 其实这是一道简单题啊. 对于树边直接lca求距离. 由于非树边最多21条. 因 ...

  6. Educational Codeforces Round 51 (Rated for Div. 2) The Shortest Statement

    题目链接:The Shortest Statement 今天又在群里看到一个同学问$n$个$n$条边,怎么查询两点直接最短路.看来这种题还挺常见的. 为什么最终答案要从42个点的最短路(到$x,y$) ...

  7. The Shortest Statement CodeForces - 1051F(待测试)

    #include <iostream> #include <cstdio> #include <sstream> #include <cstring> ...

  8. CodeForces - 837E - Vasya's Function | Educational Codeforces Round 26

    /* CodeForces - 837E - Vasya's Function [ 数论 ] | Educational Codeforces Round 26 题意: f(a, 0) = 0; f( ...

  9. CodeForces - 1051E :Vasya and Big Integers(Z算法 & DP )

    题意:给定字符串S,A,B.现在让你对S进行切割,使得每个切割出来的部分在[A,B]范围内,问方案数. 思路:有方程,dp[i]=Σ dp[j]   (S[j+1,i]在合法范围内).    假设M和 ...

随机推荐

  1. 【BZOJ】1023: [SHOI2008]cactus仙人掌图 静态仙人掌(DFS树)

    [题意]给定仙人掌图(每条边至多在一个简单环上),求直径(最长的点对最短路径).n<=50000,m<=10^7. [算法]DFS树处理仙人掌 [题解]参考:仙人掌相关问题的处理方法(未完 ...

  2. 去除UITableView多余的seperator

    UIView *v = [[UIView alloc] initWithFrame:CGRectZero]; [tableView setTableFooterView:v]; [v release] ...

  3. select多选框

    select多选框 效果: 代码: <HTML> <HEAD> <TITLE>选择下拉菜单</TITLE> <meta http-equiv=&q ...

  4. 【leetcode 简单】第三十八题 两数之和 II - 输入有序数组

    给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数. 函数应该返回这两个下标值index1 和 index2,其中 index1 必须小于 index2. 说明: 返回的下标值( ...

  5. 基于canvas的图片编辑合成器

    在我们日常的前端开发中,经常会要给服务器上传图片,但是局限很大,图片只能是已有的,假设我想把多张图片合成一张上传就需要借助图片编辑器了,但是现在我们有了canvas合成就简单多了 首先我们看图片编辑器 ...

  6. 某团队线下赛AWD writeup&Beescms_V4.0代码审计

    还是跟上篇一样.拿别人比赛的来玩一下.  0x01 预留后门 连接方式: 0x02 后台登录口SQL注入 admin/login.php 在func.php当中找到定义的check_login函数 很 ...

  7. Opencv 配置VS2012

    开始接触图像处理有一段时间了,经过前期的调研,和相关入门知识的学习,开始接触一些图像处理应用的工具.Opencv是一个图像处理的开源库,由于其开放的协议架构,国内外很多科研机构和团队都在基于openc ...

  8. MySQL指定使用某个索引查询语句

    查询语句查询emp_no,所以先查询emp_no的索引使用primary select emp_no,salary from salaries use index(s_f_t) where emp_n ...

  9. PHP利用rand(1,100)函数产生10个1~100之间的随机数

    //echo rand(1,100); $max=0; $min=100; for($i=0;$i<=9;$i++){ $rand[$i]=rand(1,100); if($rand[$i]&g ...

  10. .pnts点云

    一种3d tiles格式 MIME格式: <configuration> <system.webServer> <staticContent> <remove ...