出乎意料的一次考试,第一题二分的左界初始化错了,本来是找两个石头间的最短距离然而只有50分,最后改成0就过了,心痛。。。
跳石头
题目背景
一年一度的“跳石头”比赛又要开始了!
题目描述
这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石。组委会已经选择好了两块岩石作为比赛起点和终点。在起点和终点之间,有 NNN 块岩石(不含起点和终点的岩石)。在比赛过程中,选手们将从起点出发,每一步跳向相邻的岩石,直至到达终点。
为了提高比赛难度,组委会计划移走一些岩石,使得选手们在比赛过程中的最短跳跃距离尽可能长。由于预算限制,组委会至多从起点和终点之间移走 MMM 块岩石(不能移走起点和终点的岩石)。
输入输出格式
输入格式:第一行包含三个整数 L,N,ML,N,ML,N,M,分别表示起点到终点的距离,起点和终点之间的岩石数,以及组委会至多移走的岩石数。保证 L≥1L geq 1L≥1 且 N≥M≥0N geq M geq 0N≥M≥0。
接下来 NNN 行,每行一个整数,第 iii 行的整数 Di(0<Di<L)D_i( 0 < D_i < L)Di(0<Di<L), 表示第 iii 块岩石与起点的距离。这些岩石按与起点距离从小到大的顺序给出,且不会有两个岩石出现在同一个位置。
输出格式:一个整数,即最短跳跃距离的最大值。
输入输出样例
说明
输入输出样例 1 说明:将与起点距离为 222和 141414 的两个岩石移走后,最短的跳跃距离为 444(从与起点距离 171717 的岩石跳到距离 212121 的岩石,或者从距离 212121 的岩石跳到终点)。
另:对于 20%20\%20%的数据,0≤M≤N≤100 ≤ M ≤ N ≤ 100≤M≤N≤10。
对于50%50\%50%的数据,0≤M≤N≤1000 ≤ M ≤ N ≤ 1000≤M≤N≤100。
对于 100%100\%100%的数据,0≤M≤N≤50,000,1≤L≤1,000,000,0000 ≤ M ≤ N ≤ 50,000,1 ≤ L ≤ 1,000,000,0000≤M≤N≤50,000,1≤L≤1,000,000,000。
1 // luogu-judger-enable-o2 2 #include<bits/stdc++.h> 3 using namespace std; 4 const int maxn=50100; 5 int a[maxn],l,n,m; 6 7 bool pd(int x) 8 { 9 int zb=0,tot=0; 10 for(int i=1;i<=n;i++) 11 { 12 if(a[i]-zb>=x) zb=a[i]; 13 else tot++; 14 } 15 return tot<=m; 16 } 17 18 int main() 19 { 20 //freopen("input.txt","r",stdin); 21 int left=0,right=0; 22 scanf("%d%d%d",&l,&n,&m); 23 for(int i=1;i<=n;i++) 24 { 25 scanf("%d",&a[i]); 26 } 27 right=l; 28 while(left<=right) 29 { 30 int mid=(left+right)>>1; 31 if(!pd(mid)) right=mid-1; 32 else left=mid+1; 33 } 34 printf("%d",left-1); 35 return 0; 36 }
二分答案再判断,挺水的一题。。
子串
题目描述
有两个仅包含小写英文字母的字符串 AAA 和 BBB。
现在要从字符串 AAA 中取出 kkk 个互不重叠的非空子串,然后把这 kkk 个子串按照其在字符串 AAA 中出现的顺序依次连接起来得到一个新的字符串。请问有多少种方案可以使得这个新串与字符串 BBB 相等?
注意:子串取出的位置不同也认为是不同的方案。
输入输出格式
输入格式:第一行是三个正整数 n,m,kn,m,kn,m,k,分别表示字符串 AAA 的长度,字符串 BBB 的长度,以及问题描述中所提到的 kkk,每两个整数之间用一个空格隔开。
第二行包含一个长度为 nnn 的字符串,表示字符串 AAA。
第三行包含一个长度为 mmm 的字符串,表示字符串 BBB。
输出格式:一个整数,表示所求方案数。
由于答案可能很大,所以这里要求输出答案对 100000000710000000071000000007 取模的结果。
输入输出样例
说明
对于第 1 组数据:1≤n≤500,1≤m≤50,k=11≤n≤500,1≤m≤50,k=11≤n≤500,1≤m≤50,k=1;
对于第 2 组至第 3 组数据:1≤n≤500,1≤m≤50,k=21≤n≤500,1≤m≤50,k=21≤n≤500,1≤m≤50,k=2;
对于第 4 组至第 5 组数据:1≤n≤500,1≤m≤50,k=m1≤n≤500,1≤m≤50,k=m1≤n≤500,1≤m≤50,k=m;
对于第 1 组至第 7 组数据:1≤n≤500,1≤m≤50,1≤k≤m1≤n≤500,1≤m≤50,1≤k≤m1≤n≤500,1≤m≤50,1≤k≤m;
对于第 1 组至第 9 组数据:1≤n≤1000,1≤m≤100,1≤k≤m1≤n≤1000,1≤m≤100,1≤k≤m1≤n≤1000,1≤m≤100,1≤k≤m;
对于所有 10 组数据:1≤n≤1000,1≤m≤200,1≤k≤m1≤n≤1000,1≤m≤200,1≤k≤m1≤n≤1000,1≤m≤200,1≤k≤m。
dp题但当时没想出如何表示状态
后来讲了后才豁然开朗。。
用dp[i][j][k][0/1] 表示a选到第i个,b选到第j个,正在选第k个字串,0表示当前不选,1表示要选,因为4微要炸,把第一维进行滚动;转移的话意会下就好了
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn = 1e3+5; 4 const int mod=1000000007; 5 int n,m,k,dp[2][maxn][maxn][2]; 6 7 char a[maxn],b[maxn]; 8 9 int main(){ 10 scanf("%d%d%d",&n,&m,&k); 11 scanf("%s%s",a+1,b+1); 12 dp[0][0][0][0]=dp[1][0][0][0]=1; 13 for(int i=1;i<=n;i++) 14 for(int j=1;j<=m;j++) 15 for(int p=1;p<=k;p++){ 16 dp[i%2][j][p][0] = (dp[(i-1)%2][j][p][0] + dp[(i-1)%2][j][p][1]) % mod; 17 if(a[i]==b[j]) dp[i%2][j][p][1] = ((dp[(i-1)%2][j-1][p][1] + dp[(i-1)%2][j-1][p-1][0]) % mod + dp[(i-1)%2][j-1][p-1][1]) % mod;//注意要摸两次,只摸一次我只有60分(洛谷测的 18 else dp[i%2][j][p][1]=0; 19 } 20 printf("%d",(dp[n%2][m][k][1]+dp[n%2][m][k][0])%mod); 21 return 0; 22 }
运输计划
题目背景
公元 204420442044 年,人类进入了宇宙纪元。
题目描述
公元204420442044 年,人类进入了宇宙纪元。
L 国有 nnn 个星球,还有 n−1n-1n−1 条双向航道,每条航道建立在两个星球之间,这 n−1n-1n−1 条航道连通了 LLL 国的所有星球。
小 P 掌管一家物流公司, 该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 uiu_iui 号星球沿最快的宇航路径飞行到 viv_ivi 号星球去。显然,飞船驶过一条航道是需要时间的,对于航道 jjj,任意飞船驶过它所花费的时间为 tjt_jtj,并且任意两艘飞船之间不会产生任何干扰。
为了鼓励科技创新, LLL 国国王同意小 PPP 的物流公司参与 LLL 国的航道建设,即允许小PPP 把某一条航道改造成虫洞,飞船驶过虫洞不消耗时间。
在虫洞的建设完成前小 P 的物流公司就预接了 mmm 个运输计划。在虫洞建设完成后,这 mmm 个运输计划会同时开始,所有飞船一起出发。当这 mmm 个运输计划都完成时,小 PPP 的物流公司的阶段性工作就完成了。
如果小 PPP 可以自由选择将哪一条航道改造成虫洞, 试求出小 PPP 的物流公司完成阶段性工作所需要的最短时间是多少?
输入输出格式
输入格式:第一行包括两个正整数 n,mn, mn,m,表示 L 国中星球的数量及小 P 公司预接的运输计划的数量,星球从 111 到 nnn 编号。
接下来 n−1n-1n−1 行描述航道的建设情况,其中第 iii 行包含三个整数 ai,bia_i, b_iai,bi 和 tit_iti,表示第 iii 条双向航道修建在 aia_iai 与 bib_ibi 两个星球之间,任意飞船驶过它所花费的时间为 tit_iti。数据保证 1≤ai,bi≤n1 leq a_i,b_i leq n1≤ai,bi≤n 且 0≤ti≤10000 leq t_i leq 10000≤ti≤1000。
接下来 mmm 行描述运输计划的情况,其中第 jjj 行包含两个正整数 uju_juj 和 vjv_jvj,表示第 jjj 个运输计划是从 uju_juj 号星球飞往 vjv_jvj号星球。数据保证 1≤ui,vi≤n1 leq u_i,v_i leq n1≤ui,vi≤n
输出格式:一个整数,表示小 PPP 的物流公司完成阶段性工作所需要的最短时间。
输入输出样例
说明
所有测试数据的范围和特点如下表所示
请注意常数因子带来的程序效率上的影响。
正正经经的一个压轴题,但一些知识到位了还是能做
1.lca用来找距离,并维护一些标记,我用的倍增
2.树上差分,与lca一起用,在起始点与终点处加一,lca处减二(因为是边的差分
3.外层套个二分,枚举答案进行判断。大功告成
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn = 3e5+10; 4 inline int read(){ 5 int x=0,f=1;char ch=getchar(); 6 while(ch>'9'||ch<'0') {if(ch=='-') f=-1;ch=getchar();} 7 while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();} 8 return f*x; 9 } 10 11 int dp[maxn][26],maxd,head[maxn],size=0,deep[maxn],dis[maxn],id[maxn],cnt=0,k,tmp[maxn],n,m; 12 13 struct node{ 14 int u,v,lcaa,diss; 15 }lu[maxn]; 16 17 struct edge{ 18 int v,nex,w; 19 }e[maxn<<1]; 20 21 void adde(int u,int v,int w){e[size].v=v;e[size].w=w;e[size].nex=head[u];head[u]=size++;} 22 23 void dfs(int u){ 24 if(dp[u][0]!=-1) maxd=max(maxd,deep[u]=deep[dp[u][0]]+1); 25 id[++cnt]=u; 26 for(int i=head[u];~i;i=e[i].nex){ 27 int v=e[i].v; 28 if(dp[u][0]==v) continue; 29 dis[v]=dis[u]+e[i].w; 30 dp[v][0]=u; 31 dfs(v); 32 } 33 } 34 35 void doubling(){ 36 for(int j=1;j<=k;j++) 37 for(int i=1;i<=n;i++) 38 if(dp[i][j-1]!=-1) dp[i][j]=dp[dp[i][j-1]][j-1]; 39 } 40 41 int lca(int x,int y){ 42 if(deep[x]<deep[y]) swap(x,y); 43 for(int i=k;i>=0;i--) 44 if(dp[x][i]!=-1&&deep[dp[x][i]]>=deep[y]) x=dp[x][i]; 45 if(x==y) return x; 46 for(int i=k;i>=0;i--) 47 if(dp[x][i]!=dp[y][i]) { 48 x=dp[x][i],y=dp[y][i]; 49 } 50 return dp[x][0]; 51 } 52 53 bool check(int mid){ 54 int ans=0,tot=0; 55 memset(tmp,0,sizeof(tmp)); 56 for(int i=1;i<=m;i++){ 57 if(lu[i].diss>mid) tmp[lu[i].u]++,tmp[lu[i].v]++,tmp[lu[i].lcaa]-=2,ans=max(ans,lu[i].diss-mid),tot++; 58 } 59 if(tot==0) return 1; 60 for(int i=n;i>=1;i--) tmp[dp[id[i]][0]]+=tmp[id[i]]; 61 for(int i=2;i<=n;i++) if(tmp[i]==tot&&dis[i]-dis[dp[i][0]]>=ans) return 1; 62 return 0; 63 } 64 65 int main(){ 66 int l=0,r=0; 67 n=read(),m=read(); 68 memset(head,-1,sizeof(head));memset(dp,-1,sizeof(dp)); 69 for(int i=1;i<n;i++){ 70 int u=read(),v=read(),w=read();adde(u,v,w);adde(v,u,w);r+=w; 71 } 72 dfs(1); 73 k=(int) (log(maxd)/log(2)); 74 doubling(); 75 for(int i=1;i<=m;i++){ 76 int u=read(),v=read(); 77 lu[i].u=u,lu[i].v=v; 78 lu[i].lcaa=lca(u,v); 79 lu[i].diss=dis[u]+dis[v]-2*dis[lu[i].lcaa]; 80 } 81 int ans=0; 82 while(l<=r){ 83 int mid=(l+r)>>1; 84 if(check(mid)) r=mid-1,ans=mid; 85 else l=mid+1; 86 } 87 printf("%d",ans); 88 }
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn = 1e3+5; 4 const int mod=1000000007; 5 int n,m,k,dp[2][maxn][maxn][2]; 6 7 char a[maxn],b[maxn]; 8 9 int main(){ 10 scanf("%d%d%d",&n,&m,&k); 11 scanf("%s%s",a+1,b+1); 12 dp[0][0][0][0]=dp[1][0][0][0]=1; 13 for(int i=1;i<=n;i++) 14 for(int j=1;j<=m;j++) 15 for(int p=1;p<=k;p++){ 16 dp[i%2][j][p][0] = (dp[(i-1)%2][j][p][0] + dp[(i-1)%2][j][p][1]) % mod; 17 if(a[i]==b[j]) dp[i%2][j][p][1] = ((dp[(i-1)%2][j-1][p][1] + dp[(i-1)%2][j-1][p-1][0]) % mod + dp[(i-1)%2][j-1][p-1][1]) % mod; 18 else dp[i%2][j][p][1]=0; 19 } 20 printf("%d",(dp[n%2][m][k][1]+dp[n%2][