A. Two Rabbits
題意:有兩隻兔子,甲兔在點,乙兔在點,,甲兔每秒往右步,乙兔每秒往左步,判斷兩兔何時能在同一點相遇。
解析:判斷是否爲0,是輸出,否輸出。
代碼:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int T;
int main()
{
ios::sync_with_stdio(false);
cin>>T;
while(T--)
{
ll x,y,a,b,d,k;
cin>>x>>y>>a>>b;
d=y-x,k=a+b;
cout<<(d%k?-1:d/k)<<"\n";
}
}
B. Longest Palindrome
題意:求出在個長度爲的互不相同的字符串中挑選任意個字符串組合成的最長迴文串。
解析:把所有字符串放進裏,然後統計一個字符串後是否在裏,有則加到答案裏。注意要特判該字符串是否迴文,然後把最長迴文串加入答案字符串中間。
代碼:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
string s[111];
set<string> se;
int n,m,sum,now;
int mx,id;//記錄最長的迴文串長度和下標
string ans[111];//答案字符串
int main()
{
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=0;i<n;i++)cin>>s[i],se.insert(s[i]);
for(int i=0;i<n;i++)
{
if(!se.count(s[i]))continue;
string t=s[i];
reverse(t.begin(),t.end());
if(t==s[i]&&t.size()>mx)
{
mx=t.size();
id=i;
}
else if(se.count(t))
{
sum+=s[i].size()*2;
ans[now]=s[i];
ans[n-now-1]=t;
se.erase(t);
now++;
}
se.erase(s[i]);
}
cout<<sum+mx<<"\n";
if(sum+mx!=0)
{
for(int i=0;i<now;i++)cout<<ans[i];
if(mx)cout<<s[id];
for(int i=n-1-now+1;i<n;i++)cout<<ans[i];
}
}
C. Air Conditioner
題意:個客人,每個客人有三種屬性,表示客人在時來到,要求此時空調溫度在之內,空調溫度初始(時)爲,判斷是否能滿足所有客人的需求。
解析:直接按時間順序更新溫度可能到達的上下界,若不可能在內就是NO。有一說一,這題應該相當於平時Div2B的難度,算是比較送分了。
代碼:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int T,n;
ll m;
struct node
{
ll t,l,r;
bool operator < (const node &s)
{
return t<s.t;
}
}a[111];
int main()
{
ios::sync_with_stdio(false);
cin>>T;
while(T--)
{
cin>>n>>m;
ll l=m,r=m,t=0;
int flag=0;
for(int i=1;i<=n;i++)
cin>>a[i].t>>a[i].l>>a[i].r;
sort(a+1,a+1+n);//按時間排序
for(int i=1;i<=n;i++)
{
ll d=a[i].t-t;//表示此時空調溫度最大可以變化d
if(r+d<a[i].l||l-d>a[i].r)flag=1;
r=min(r+d,a[i].r);//更新邊界
l=max(l-d,a[i].l);//更新邊界
t=a[i].t;
}
cout<<(flag?"NO":"YES")<<"\n";
}
}
D. Shortest and Longest LIS
題意:給定一個整數和一個由"“和”"組成的長度爲的字符串,爲一個的排列,的第位若爲,則有,若爲,則有。要求構造出(最長上升子序列)最短and最長且符合字符串限制的。
解析A:比賽時想到的樹狀數組+貪心亂搞方法。如果要使儘可能短,則要讓位置在前面的數儘可能大,後面的數儘可能小。因此我們可以遍歷一遍,遇到就要讓前面所有數爲然後把當前的數置爲,遇到也要把之前的所有數,同時令當前數設置爲前一個數,符合貪心策略,區間加就用樹狀數組維護。最長同理。
代碼A:
#include <bits/stdc++.h>
#define N 200010
#define ll long long
using namespace std;
int T,n;
string s;
int c[N],d[N];
int lowbit(int x){return x&(-x);}
void add(int l,int r,int x)//a[l:r]+=x;
{
for(int i=l;i<=n;i+=lowbit(i))c[i]+=1ll*x,d[i]+=1ll*l*x;
for(int i=r+1;i<=n;i+=lowbit(i))c[i]-=1ll*x,d[i]-=(r+1ll)*x;
}
int query(int l,int r)//sum of a[l]~a[r]
{
int ans=0;
for(int i=l-1;i;i-=lowbit(i))ans-=1ll*l*c[i]-d[i];
for(int i=r;i;i-=lowbit(i))ans+=(r+1ll)*c[i]-d[i];
return ans;
}
int main()
{
ios::sync_with_stdio(false);
cin>>T;
while(T--)
{
cin>>n>>s;
for(int i=1;i<=n;i++)c[i]=d[i]=0;
add(1,1,1);
int pre=0;
for(int i=1;i<=s.size();i++)
{
if(s[i-1]=='>')
{
pre=i;
add(1,i,1);
add(i+1,i+1,1);
}
else
{
if(pre)add(1,pre,1);
add(i+1,i+1,query(i,i)+1);
}
}
for(int i=1;i<=n;i++)cout<<query(i,i)<<(i==n?"\n":" ");
for(int i=1;i<=n;i++)c[i]=d[i]=0;
add(1,1,1);
pre=1;
for(int i=1;i<=s.size();i++)
{
if(s[i-1]=='<')
{
add(i+1,i+1,i+1);
pre=i+1;
}
else
{
add(pre,i,1);
add(i+1,i+1,query(i,i)-1);
}
}
for(int i=1;i<=n;i++)cout<<query(i,i)<<(i==n?"\n":" ");
}
}
解析B:賽後聽winterzz1大佬說的方法。直接記錄相鄰數字的相對大小,增減分別用與(一個足夠大的數)表示,離散化後就是答案(winterzz1tql!)。
代碼B:
#include <bits/stdc++.h>
#define N 200010
#define INF 0x3f3f3f3f
#define ll long long
using namespace std;
int n,m;
ll a[N],b[N],c[N];
string s;
void discret(ll *a,ll n)//將a離散化,O(nlogn)
{
for(int i=1;i<=n;i++)c[i]=a[i];
sort(c+1,c+1+n);
for(int i=1;i<=n;i++)a[i]=lower_bound(c+1,c+1+n,a[i])-c;
}
int main()
{
ios::sync_with_stdio(false);
int T;
cin>>T;
while(T--)
{
cin>>n>>s;
for(int i=2;i<=n;i++)
{
if(s[i-2]=='<')
{
a[i]=a[i-1]+1;
b[i]=b[i-1]+INF;
}
else
{
a[i]=a[i-1]-INF;
b[i]=b[i-1]-1;
}
}
discret(a,n);
discret(b,n);
for(int i=1;i<=n;i++)cout<<a[i]<<(i==n?"\n":" ");
for(int i=1;i<=n;i++)cout<<b[i]<<(i==n?"\n":" ");
}
}
解析C:也是聽大佬說的方法,但是自己沒(bu)去(hui)實現。長度爲的排列中,最短的情況是,如果爲,我們只需要翻轉區間,得到的答案爲。也就是說可以通過翻轉所有的區間即可得到答案,具體的翻轉操作要用線段樹實現(不會所以沒寫QAQ,下次一定學)。
E. 1-Trees and Queries
題意:給定一個點條邊的樹,有個詢問,每個詢問有五個數,表示詢問在之間加一條邊的話,是否存在到長度爲的路(每個點和邊都可以重複經過)。
解析:由於可以重複,在到之間長度小於的情況下就可以任選路徑上的一個邊反覆橫跳,也就是說只要滿足到的長度和的奇偶性相同即可。多了一條到的邊,之前之間的路徑就多了兩種可能:和,我們只需要判斷三條路徑是否有一條的長度和奇偶性相同,樹上兩點的距離等於,爲深度,爲的最近公共祖先。
代碼:
#include <bits/stdc++.h>
#define N 200010
#define pb push_back
#define ll long long
#define VI vector<int>
using namespace std;
int n,m,q,fa[N][20],dep[N];
bool vis[N];
VI G[N];
void dfs(int u,int pre)
{
dep[u]=dep[pre]+1;
vis[u]=1;
fa[u][0]=pre;
for(int v:G[u])
if(!vis[v])
dfs(v,u);
}
void init(int n)//O(NlogN)
{
for(int i=1;(1<<i)<=n;i++)
for(int j=1;j<=n;j++)
fa[j][i]=fa[fa[j][i-1]][i-1];
}
int lca(int u,int v)//O(logN)
{
if(dep[u]<dep[v])swap(u,v);
int d=dep[u]-dep[v];
for(int i=0;(1<<i)<=d;i++)
if(d&(1<<i))u=fa[u][i];
if(u==v)return u;
for(int i=17;i>=0;i--)
if(fa[u][i]!=fa[v][i])u=fa[u][i],v=fa[v][i];
return fa[u][0];
}
int dis(int u,int v)
{
return dep[u]+dep[v]-2*dep[lca(u,v)];
}
int main()
{
ios::sync_with_stdio(false);
cin>>n;m=n-1;
for(int i=1;i<=m;i++)
{
int u,v;
cin>>u>>v;
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1,1);
init(n);
cin>>q;
while(q--)
{
int x,y,a,b,k,d[3],flag=1;
cin>>x>>y>>a>>b>>k;
d[0]=dis(a,b);
d[1]=dis(a,x)+dis(b,y)+1;
d[2]=dis(x,b)+dis(a,y)+1;
for(int i=0;i<3;i++)
if(d[i]<=k&&(k-d[i])%2==0)
flag=0;
cout<<(flag?"NO":"YES")<<"\n";
}
}
F題待補。。。