Gildong厌倦了参加过多次Codeforce攻击,决定在公园休息一下。他坐在长凳上,很快他发现两只兔子在跳来跳去。一只兔子比另一只更高。
他注意到两只兔子在互相跳来跳去。两只兔子的位置可以表示为水平线上的整数坐标。较高的兔子当前位于位置x,而较短的兔子当前位于位置y(x <y)。每秒钟,每只兔子跳到另一个位置。较高的兔子跳向a的正向,而较短的兔子跳向b的负向。
例如,假设x = 0,y = 10,a = 2和b = 3。在第1秒,每只兔子将在位置2和7。在第2秒,两只兔子将在位置4。
Gildong现在在想:两只兔子会在同一时刻处于同一位置吗?如果是这样,需要多长时间?让我们找到一个时间点(以秒为单位),在那之后兔子将处于同一点。
输入值 每个测试包含一个或多个测试用例。第一行包含测试用例的数量t(1≤t≤1000)。
每个测试用例仅包含一行。该行由四个整数x,y,a,b(0≤x<y≤109,1≤a,b≤109)-高兔子的当前位置,矮兔子的当前位置,跳跃距离高兔子的跳动距离和短兔子的跳动距离。
输出量 对于每个测试用例,请打印一个整数:两只兔子在同一位置所花费的秒数。
如果两只兔子永远不会同时在同一位置,请打印-1。
题解:
简单模拟
#include<bits/stdc++.h> using namespace std; int a,b,x,y; int main () { int T; scanf("%d",&T); while (T--) { scanf("%d%d%d%d",&a,&b,&x,&y); if ((b-a!=0)&&(x+y==0)) { printf ("-1 "); continue; } if (b-a==0) { printf ("0 "); continue; } if ((b-a)%(x+y)==0) { printf ("%d ",(b-a)/(x+y)); continue; } printf ("-1 "); } return 0; }
回到解决问题的方向,吉尔东现在正在研究回文。他了解到回文是与反向字符串相同的字符串。例如,字符串“ pop”,“ noon”,“ x”和“ kkkkkk”是回文,而字符串“ moon”,“ tv”和“ abab”则不是。空字符串也是回文。
Gildong非常喜欢这个概念,所以他想玩这个游戏。他有n个等长的m个不同的弦。他想丢弃某些字符串(可能没有或全部),并对其余的字符串重新排序,以使串联成为回文。他还希望回文期尽可能长。请帮助他找到一个。
输入值 第一行包含两个整数n和m(1≤n≤100,1≤m≤50)-字符串数和每个字符串的长度。
接下来的n行包含一个长度为m的字符串,仅由小写拉丁字母组成。所有字符串都是不同的。
输出量 在第一行中,打印您制作的最长回文字符串的长度。
在第二行中,打印该回文。如果有多个答案,请打印其中一个。如果回文为空,则打印空白行或根本不打印此行。
题解:
#include<bits/stdc++.h> using namespace std; int N,M; string s1,s2; unordered_set<string> st; int main () { scanf("%d%d",&N,&M); for (int i=0;i<N;i++) { string t; cin>>t; st.insert(t); string r=t; reverse(r.begin(),r.end()); if (t==r) s1=t; else if (st.count(r)) s2+=t; } string t=s2; reverse(t.begin(),t.end()); s2+=s1+t; printf ("%d ",s2.length()); cout<<s2<<" "; return 0; }
吉东拥有一家烤肉餐厅。这家餐厅有很多顾客,所以很多人喜欢在参观之前进行预订。
Gildong尽力满足客户需求,甚至还记住了所有客户的首选温度范围!通过查看预订列表,他想通过控制餐厅的温度来满足所有顾客的需求。
该餐厅的空调有3种状态:关闭,加热和冷却。关闭时,餐厅的温度保持不变。加热时,温度在一分钟内升高1。最后,在冷却时,温度在一分钟内降低1。吉尔东可以在任何整数分钟内随意更改状态。空调最初关闭。
每个客户都具有三个值:ti-第i位客户访问餐厅的时间(分钟),li-首选温度范围的下限,hi-首选温度范围的上限。
如果顾客在去餐厅的那一刻温度在优选范围内,那么顾客会感到满意。正式地,第i个客户只有在第10分钟内温度在li和hi(含)之间时才满意。
给定初始温度,保留客户的访问时间列表及其首选的温度范围,您将帮助他确定是否有可能满足所有客户的需求。
输入值 每个测试包含一个或多个测试用例。第一行包含测试用例的数量q(1≤q≤500)。测试用例的说明如下。
每个测试用例的第一行包含两个整数n和m(1≤n≤100,-109≤m≤109),其中n是预订客户的数量,m是餐厅的初始温度。
接下来,n行。它们的第i行包含三个整数ti,li和hi(1≤ti≤109,−109≤li≤hi≤109),其中ti是第i个客户访问的时间,li是较低的hi是其首选温度范围的上限。hi是其首选温度范围的上限。优选的温度范围包括两端。
客户的访问时间以不降序排列,当前时间为0。
输出量 对于每个测试用例,如果有可能使所有客户满意,则打印“是”。否则,打印“否”。
您可以在任何情况下(大写或小写)打印每个字母。
题解:
#include<bits/stdc++.h> using namespace std; int N,M; struct node { int t; int l; int r; }; vector<node> vi; bool cmp (node a,node b) { if (a.t!=b.t) return a.t<b.t; else if (a.l!=b.l) return a.l<b.l; else return a.r<b.r; } void solve () { vi.clear(); scanf("%d%d",&N,&M); int L=M,R=M; for (int i=0;i<N;i++) { int t,l,r; scanf("%d%d%d",&t,&l,&r); vi.push_back({t,l,r}); } sort(vi.begin(),vi.end(),cmp); for (int i=0;i<N;i++) { int t=vi[i].t; if (i!=0) t-=vi[i-1].t; L=max(L-t,vi[i].l); R=min(R+t,vi[i].r); if (L>R) { printf ("NO "); return; } } printf ("YES "); } int main () { int T; scanf("%d",&T); while (T--) solve(); return 0; }
Gildong最近学习了如何在O(nlogn)时间中找到长度为n的序列中最长的递增子序列(LIS)。他想测试自己是否可以正确实施,但是他找不到任何在线法官可以做到(即使实际上有很多法官)。因此,相反,他将为您做一个关于在1到n之间(含1和n)的n个不同整数进行排列的测验,以用您的输出测试他的代码。
测验如下。
Gildong提供了一个长度为n-1的字符串,仅由字符“ <”和“>”组成。第i个(1索引)字符是序列中第i个元素和第i + 1个元素之间的比较结果。如果字符串的第i个字符是“ <”,则序列中的第i个元素小于第i + 1个元素。如果字符串的第i个字符是'>',则序列中的第i个元素大于第i + 1个元素。
他希望您找到两个可能的序列(不一定是不同的),这些序列由介于1和n之间(含端点)的n个不同的整数组成,每个整数都满足比较结果,其中第一个序列的LIS长度最小,而第一个序列的LIS长度最小。第二序列的LIS是最大可能的。
输入值 每个测试包含一个或多个测试用例。第一行包含测试用例的数量t(1≤t≤104)。
每个测试用例仅包含一行,该行由一个整数和一个仅由字符“ <”和“>”组成的字符串组成。整数是n(2≤n≤2⋅105),这是您需要查找的排列的长度。该字符串是描述中说明的比较结果。字符串的长度为n-1。
确保所有测试用例中所有n的总和不超过2⋅105。
输出量 对于每个测试用例,打印两行,每行n个整数。第一行是具有最小长度的LIS的序列,第二行是具有最大长度的LIS的序列。如果有多个答案,请打印其中一个。每个序列应包含1到n之间的所有整数(含1和n),并且应满足比较结果。
可以证明,至少存在一个答案。
题解:
#include<bits/stdc++.h> using namespace std; const int maxn=1e6+14; int T; int N; int p[maxn]; char s[maxn]; int main () { scanf("%d",&T); while (T--) { scanf("%d%s",&N,s+1); for (int i=1;i<=N;i++) p[i]=N-i+1; for (int i=1;i<N;) { int j=i; while (s[j]=='<') j++; reverse(p+i,p+j+1); i=j+1; } for (int i=1;i<=N;i++) printf ("%d ",p[i]); printf (" "); for (int i=1;i<=N;i++) p[i]=i; for (int i=1;i<N;) { int j=i; while (s[j]=='>') j++; reverse(p+i,p+j+1); i=j+1; } for (int i=1;i<=N;i++) printf ("%d ",p[i]); printf (" "); } return 0; }
吉尔东(Gildong)正在远足一座山,在数以百万计的树木中行走。受到他们的启发,他突然想出了一个关于数据结构树的有趣想法:如果我们在树中添加另一条边怎么办?
然后他发现这种树状图称为1树。由于Gildong厌倦了解决太多树木问题的工作,他想看看是否也可以在1棵树中使用类似的树木技术。他将通过在1树上提供查询来测试您,而不是自己解决问题。
首先,他将为您提供一棵具有n个顶点的树(非1树),然后他会问您q个查询。每个查询包含5个整数:x,y,a,b和k。这意味着在顶点x和y之间添加双向边后,系统会要求您确定是否存在从顶点a到b的路径,该路径正好包含k个边。路径可以多次包含相同的顶点和相同的边。所有查询彼此独立;即在查询中添加的边在下一个查询中被删除。
输入值 第一行包含整数n(3≤n≤105),即树的顶点数。
接下来的n-1行分别包含两个整数u和v(1≤u,v≤n,u≠v),这意味着顶点u和v之间存在一条边。所有边都是双向且互不相同的。
下一行包含整数q(1≤q≤105),这是Gildong要询问的查询数。
接下来的q行分别包含五个整数x,y,a,b和k(1≤x,y,a,b≤n,x≠y,1≤k≤109)–在说明中说明的整数。可以确保原始树中不存在x和y之间的边。
输出量 对于每个查询,如果在x和y顶点之间添加了一条边后,如果存在一条路径,该路径恰好包含从顶点a到b的k条边,则打印“ YES”。否则,打印“否”。
您可以在任何情况下(大写或小写)打印每个字母。
题解:
#include<bits/stdc++.h> using namespace std; const int maxn=1e6+14; int N,Q; int father[18][maxn]; int h[maxn]; vector<int> g[maxn]; void dfs (int x) { for (int i=0;i<g[x].size();i++) { int v=g[x][i]; if (v==father[0][x]) continue; father[0][v]=x; h[v]=h[x]+1; dfs(v); } } int lca (int x,int y) { if (h[x]<h[y]) swap(x,y); for (int i=17;i>=0;i--) { if (h[x]-h[y]>>i) x=father[i][x]; } if (x==y) return x; for (int i=17;i>=0;i--) { if (father[i][x]!=father[i][y]) { x=father[i][x]; y=father[i][y]; } } return father[0][x]; } int getDis (int x,int y) { return h[x]+h[y]-h[lca(x,y)]*2; } bool check (int x,int y) { return y>=x&&x%2==y%2; } int main () { scanf("%d",&N); for (int i=1;i<N;i++) { int a,b; scanf("%d%d",&a,&b); g[a].push_back(b); g[b].push_back(a); } dfs(1); for (int i=1;i<=17;i++) { for (int j=1;j<=N;j++) father[i][j]=father[i-1][father[i-1][j]]; } scanf("%d",&Q); for (int i=0;i<Q;i++) { int x,y,a,b,k; scanf("%d%d%d%d%d",&x,&y,&a,&b,&k); if (check(getDis(a,b),k)|| check(getDis(a,x)+getDis(y,b)+1,k)|| check(getDis(a,y)+getDis(x,b)+1,k)) printf ("YES "); else printf ("NO "); } return 0; }
吉尔东(Gildong)喜欢观察动物,因此他购买了两个照相机,以拍摄森林中野生动物的视频。一台摄像机的颜色是红色,另一台摄像机的颜色是蓝色。
从第1天到第n天,Gildong将拍摄n天的视频。森林可以分为m个区域,编号从1到m。他将通过以下方式使用相机:
在每个奇数天(1日,3日,5日...),将红色相机带到森林中并录制2天的视频。 在每天的偶数日(第2、4、6等),将蓝色相机带到森林中并录制2天的视频。 如果他在第n天使用其中一台摄像机开始录制,则该摄像机仅录制一天。 每个摄像机可以观察森林的k个连续区域。例如,如果m = 5且k = 3,则他可以放置相机观察这三个区域范围之一,持续两天:[1,3],[2,4]和[3,5]。
Gildong获得了有关每天在每个区域看到多少动物的信息。由于他想观察尽可能多的动物,因此他希望您找到放置两台摄像机n天的最佳方法。请注意,如果两个摄像机在同一天观察同一区域,则在该区域观察到的动物仅被计数一次。
输入值 第一行包含三个整数n,m和k(1≤n≤50、1≤m≤2⋅104、1≤k≤m)– Gildong将要记录的天数,森林,以及摄像机的范围。
接下来的n行每个包含m个整数。第i + 1行中的第j个整数是在第j个区域的第i天可以看到的动物数量。动物的数量在0到1000之间(含0和1000)。
输出量 打印一个整数-可以观察到的最大动物数量。
题解:
#include<bits/stdc++.h> using namespace std; const int maxn=20014; struct node { int l; int r; int mx; int tag; }segTree[maxn*4]; int N,M,K; int a[60][maxn]; int sum[60][maxn]; int dp[60][maxn]; void build (int i,int l,int r,int x) { segTree[i].l=l; segTree[i].r=r; segTree[i].tag=0; if (l==r-1) segTree[i].mx=dp[x-1][l]+sum[x][l+K-1]-sum[x][max(K-1,l-1)]; else { int mid=(l+r)>>1; build(i<<1,l,mid,x); build(i<<1|1,mid,r,x); segTree[i].mx=max(segTree[i<<1].mx,segTree[i<<1|1].mx); } } void update (int i) { segTree[i<<1].mx+=segTree[i].tag; segTree[i<<1|1].mx+=segTree[i].tag; segTree[i<<1].tag+=segTree[i].tag; segTree[i<<1|1].tag+=segTree[i].tag; segTree[i].tag=0; } void modify (int i,int l,int r,int del) { if (l<=segTree[i].l&&r>=segTree[i].r) { segTree[i].mx+=del; segTree[i].tag+=del; return; } if (segTree[i].tag) update(i); int mid=(segTree[i].l+segTree[i].r)>>1; if (l<mid) modify(i<<1,l,r,del); if (r>mid) modify(i<<1|1,l,r,del); segTree[i].mx=max(segTree[i<<1].mx,segTree[i<<1|1].mx); } void solve () { scanf("%d%d%d",&N,&M,&K); for (int i=1;i<=N;i++) { sum[i][0]=0; for (int j=1;j<=M;j++) { scanf("%d",&a[i][j]); sum[i][j]=sum[i][j-1]+a[i][j]; } } for (int j=1;j<=M-K+1;j++) dp[1][j]=sum[1][j+K-1]-sum[1][j-1]; for (int i=2;i<=N;i++) { build(1,1,M-K+2,i); for (int j=1;j<=M-K+1;j++) { modify(1,j,j+K,-a[i][j+K-1]); dp[i][j]=segTree[1].mx+sum[i][j+K-1]-sum[i][j-1]; modify(1,max(j-K+1,1),j+1,a[i][j]); } } int ans=dp[N][1]; for (int j=2;j<=M;j++) ans=max(ans,dp[N][j]); printf ("%d ",ans); } int main () { solve(); return 0; }