Codeforces 1051E Vasya and Big Integers&1051F The Shortest Statement
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的更多相关文章
- Codeforces 1051E. Vasya and Big Integers
		
题意:给你N个点M条边,M-N<=20,有1e5个询问,询问两点的最短距离.保证没有自环和重边. 题解:连题目都在提示你这个20很有用,所以如果是颗树的话那任意两点的最短距离就是求一下lca搞一 ...
 - codeforces 1051F The Shortest Statement
		
题目链接:codeforces 1051F The Shortest Statement 题意:\(q\)组询问,求任意两点之间的最短路,图满足\(m-n\leq 20\) 分析:一开始看这道题:fl ...
 - [Codeforces 1051F] The Shortest Statement 解题报告(树+最短路)
		
题目链接: https://codeforces.com/contest/1051/problem/F 题目大意: 给出一张$n$个点,$m$条边的带权无向图,多次询问,每次给出$u,v$,要求输出$ ...
 - Codeforces.1051F.The Shortest Statement(最短路Dijkstra)
		
题目链接 先随便建一棵树. 如果两个点(u,v)不经过非树边,它们的dis可以直接算. 如果两个点经过非树边呢?即它们一定要经过该边的两个端点,可以直接用这两个点到 u,v 的最短路更新答案. 所以枚 ...
 - 2018.09.24 codeforces 1051F. The Shortest Statement(dijkstra+lca)
		
传送门 这真是一道一言难尽的题. 首先比赛的时候居然没想出来正解. 其次赛后调试一直调不出来最后发现是depth传错了. 其实这是一道简单题啊. 对于树边直接lca求距离. 由于非树边最多21条. 因 ...
 - Educational Codeforces Round 51 (Rated for Div. 2) The Shortest Statement
		
题目链接:The Shortest Statement 今天又在群里看到一个同学问$n$个$n$条边,怎么查询两点直接最短路.看来这种题还挺常见的. 为什么最终答案要从42个点的最短路(到$x,y$) ...
 - The Shortest Statement CodeForces - 1051F(待测试)
		
#include <iostream> #include <cstdio> #include <sstream> #include <cstring> ...
 - CodeForces - 837E - Vasya's Function   |  Educational Codeforces Round 26
		
/* CodeForces - 837E - Vasya's Function [ 数论 ] | Educational Codeforces Round 26 题意: f(a, 0) = 0; f( ...
 - CodeForces - 1051E :Vasya and Big Integers(Z算法 & DP )
		
题意:给定字符串S,A,B.现在让你对S进行切割,使得每个切割出来的部分在[A,B]范围内,问方案数. 思路:有方程,dp[i]=Σ dp[j] (S[j+1,i]在合法范围内). 假设M和 ...
 
随机推荐
- 【CodeForces】915 D. Almost Acyclic Graph 拓扑排序找环
			
[题目]D. Almost Acyclic Graph [题意]给定n个点的有向图(无重边),问能否删除一条边使得全图无环.n<=500,m<=10^5. [算法]拓扑排序 [题解]找到一 ...
 - 【CodeForces】901 C. Bipartite Segments
			
[题目]C. Bipartite Segments [题意]给定n个点m条边的无向连通图,保证不存在偶数长度的简单环.每次询问区间[l,r]中包含多少子区间[x,y]满足只保留[x,y]之间的点和边构 ...
 - Yii2 的 redis 应用
			
在应用的时候需要先对yii2进行扩展安装 如果装有composer直接运行 php composer.phar require --prefer-dist yiisoft/yii2-redis 当然也 ...
 - 51Nod - 1127  最短的包含字符串
			
给出一个字符串,求该字符串的一个子串s,s包含A-Z中的全部字母,并且s是所有符合条件的子串中最短的,输出s的长度.如果给出的字符串中并不包括A-Z中的全部字母,则输出No Solution. Inp ...
 - NYOJ   328      完全覆盖   (找规律)
			
题目链接 描述 有一天小董子在玩一种游戏----用21或12的骨牌把mn的棋盘完全覆盖.但他感觉游戏过于简单,于是就随机生成了两个方块的位置(可能相同),标记一下,标记后的方块不用覆盖.还要注意小董子 ...
 - L - SOS Gym - 101775L  博弈
			
题目链接:https://cn.vjudge.net/contest/274151#problem/L 题目大意:给你一个1*n的方格,两个人轮流放字母,每一次可以放"S"或者&q ...
 - 绿色的宠物店cms后台管理系统模板——后台
			
链接:http://pan.baidu.com/s/1c7qmsA 密码:2es8
 - perf + 火焰图分析程序性能
			
1.perf命令简要介绍 性能调优时,我们通常需要分析查找到程序百分比高的热点代码片段,这便需要使用 perf record 记录单个函数级别的统计信息,并使用 perf report 来显示统计结果 ...
 - Sqlmap与burpsuite动态更新某些参数
			
有如下注入点: http://localhost/id=1&order_nu=1 情况说明: id为注入点, 每一次注入时, order_nu不能跟上次的一样(假说这个order_nu为一个 ...
 - ThinkPHP的输出和模型使用
			
1.假设在v层需要输出一个变量怎么办呢?即如同在html当中输出php代码. 可以直接使用{$name}代替.花括号被称之为标识符.可以通过修改配置项('TMPL_L_DELIM'=>'< ...