A.Two Rabbits

题意:两只兔子一开始在x、y两点,每次相向跳a、b步,询问是否能在某一时刻相遇,如果能则输出时刻

题解:水题,直接模拟即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+5;
const int mod = 1e9+7;
const int INF = 0x3f3f3f3f;
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        ll x,y,a,b;
        scanf("%lld%lld%lld%lld",&x,&y,&a,&b);
        if((y-x)%(a+b)==0)
            printf("%lld\n",(y-x)/(a+b));
        else 
            puts("-1");
    }
    return 0;
}

B.Longest Palindrome

题意:给你n个长度为m的字符串,选择其中若干个字符串相连接,问你最长能组成多长的回文串,输出长度和字符串。

题解:发现如果存在一个自身是回文串的则将它放在中间,其余的搜索一下,对称放即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+5;
const int mod = 1e9+7;
const int INF = 0x3f3f3f3f;
map<string,int>mp;
vector<int>v;
vector<pair<int,int>>v1;
string str[105];
int vis[105];
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        string s;
        cin >> s;
        str[i]=s;
        int flag=1;
        for(int j=0;j<m/2;j++)
        {
            if(s[j]!=s[m-1-j])
            {
                flag=0;
                break;
            }
        }
        if(flag)
            v.push_back(i);
        string t;
        for(int j=m-1;j>=0;j--)
            t += s[j];
        if(mp[t])
            v1.push_back({i,mp[t]});
        else 
            mp[s]=i;
    }
    string s1,s2;
    int cnt = 0;
    for(int i=0;i<v1.size();i++)
    {
        auto it = v1[i];
        if(vis[it.first]||vis[it.second])
            continue;
        cnt += 2;
        vis[it.first]=vis[it.second]=1;
        s1 = s1 + str[it.first];
        s2 = str[it.second] + s2;
    }
    for(int i=0;i<v.size();i++)
    {
        if(!vis[v[i]])
        {
            cnt++;
            s1 = s1 + str[v[i]];
            break;
        }
    }
    printf("%d\n",m*cnt);
    cout << s1<<s2 << endl;
    return 0;
}

C.Air Conditioner(思维)

题意:一共有n个顾客,一开始餐厅温度为m,第i个顾客在第ti分钟到来,他的满意温度在li~hi,你对餐厅可以有三种操作:1、升温:每分钟升高2;2、保温:温度保持不变;3:降温:每分钟降低2。询问你是否能使所有顾客满意

题解:我们可以维护一个区间,这个区间是你所能操控餐厅温度的范围,每次和当前顾客的满意区间比较,然后更新你能操控温度的范围即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+5;
const int mod = 1e9+7;
const int INF = 0x3f3f3f3f;
struct People
{
    ll t,l,h;
    bool operator<(const People & C)const{
        return t < C.t;
    }
}p[105];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n;
        ll m;
        scanf("%d%lld",&n,&m);
        for(int i=0;i<n;i++)
            scanf("%lld%lld%lld",&p[i].t,&p[i].l,&p[i].h);
        sort(p,p+n);
        ll L = m , R = m;
        int flag = 1;
        ll t = 0;
        for(int i=0;i<n;i++)
        {
            ll cnt = p[i].t - t;
            L = L - cnt;
            R = R + cnt;
            if(R<p[i].l||L>p[i].h)
            {
                flag=0;
                break;
            }
            L = max(L,p[i].l);
            R = min(R,p[i].h);
            t = p[i].t;
        }
        if(flag)
            puts("YES");
        else
            puts("NO");
    }
    return 0;
}

D.Shortest and Longest LIS(思维+模拟)

题意:给你n-1个由'<'和'>'组成的序列,表示前后两个数的大小关系,让你构造出长度为n,由1~n中的数组成的最短上升子序列和最长上升子序列。

题解:对于最短上升子序列我们只要前一段趋势都比后一段高即可,对于最长上升子序列我们只要后一段趋势都比前一段高即可。这道题我们画出折线图比较好理解图片说明 图片说明

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
char s[N];
int n, a[N];
void getmax() {
    int L = 0, pre = 0;
    for(int i = 1; i <= n; i++) {
        if(s[i] == '>') continue;
        else {
            for(int j = i; j > pre; j--) a[j] = ++L;
            pre = i;
        }
    }
    for(int i = 1; i <= n; i++) printf("%d ", a[i]);
    printf("\n");
}
void getmin() {
    int L = n + 1, pre = 0;
    for(int i = 1; i <= n; i++) {
        if(s[i] == '<') continue;
        else {
            for(int j = i; j > pre; j--) a[j] = --L;
            pre = i;
        }
    }
    for(int i = 1; i <= n; i++) printf("%d ", a[i]);
    printf("\n");
}

int main() {
    int T; scanf("%d", &T);
    while(T--) {
        scanf("%d", &n);
        scanf(" %s", s + 1);
        getmin();
        getmax();
    }
}

E.1-Trees and Queries

题意:给你一棵n个节点的树,q组询问,每组询问给你x、y、a、b、k,表示在x和y节点之间连一条边,问你在a和b节点之间能否扎到一条长度为k的路径,其中边和点可以重复走。

题解:我们只要找一条路径,这条路径的长度小于等于k,并且奇数性与k相同即可,因为我们可以一直在两点之间来回使长度增加到k。而最短路径只会有3种情况:1、a→b;2、a→x→y→b;3、a→y→x→b。长度用lca算即可。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 7;
int n, q, f[18][maxn], 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 == f[0][x])
            continue;
        f[0][v] = x;
        h[v] = h[x] + 1;
        dfs(v);
    }
}
void lca_init()
{
    dfs(1);
    for (int i = 1; i <= 17; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            f[i][j] = f[i - 1][f[i - 1][j]];
        }
    }
}
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 = f[i][x];
        }
    }
    if (x == y)
        return x;
    for (int i = 17; i >= 0; i--)
    {
        if (f[i][x] != f[i][y])
        {
            x = f[i][x];
            y = f[i][y];
        }
    }
    return f[0][x];
}
int dis(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()
{
    cin >> n;
    for (int i = 1; i < n; i++)
    {
        int a, b;
        cin >> a >> b;
        G[a].push_back(b);
        G[b].push_back(a);
    }
    lca_init();
    cin >> q;
    for (int i = 0; i < q; i++)
    {
        int x, y, a, b, k;
        cin >> x >> y >> a >> b >> k;
        if (check(dis(a, b), k) ||
            check(dis(a, x) + dis(y, b) + 1, k) ||
            check(dis(a, y) + dis(x, b) + 1, k))
            puts("YES");
        else
            puts("NO");
    }
}

F.Animal Observation(dp+线段树)

题意:一个人去森林摄像,一共去m天,他有两台摄像机,奇数天会把一台摄像机放在一个区域,偶数天会把另一台摄像机放在一个区域,每台摄像机会放置在同一个区域连续两天,每台摄像机能拍摄k个区域,每个区域都有动物。问你最多能拍摄多少只动物

题解:dp[i][j]表示第i天把相机放在第j个区域最大能拍摄动物的数量,因为相机会连续拍摄两天,所以每个区域的影响应该包括两天,而第二天的dp[i+1][j]当天的贡献因为dp[i][j]已经算过了,所以我们在算第i+1天的时候要把dp[i][j]的第i+1的贡献减去,可以用滑动窗口来实现,因为拍摄范围是k,所以i~i+k-1都需要减去,所以我们可以用线段树来维护。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 4e4+6;
int n,m,k;
int ani[55][maxn],dp[55][maxn],sum[55][maxn];
struct node{
   int l,r;
   int mx;
   int tag;
}tr[maxn*4];
void build(int k,int s,int t)
{
    tr[k].l=s;tr[k].r=t;
    if(s==t){tr[k].mx=0;return;}
    int mid=(s+t)>>1;
    build(k<<1,s,mid);
    build(k<<1|1,mid+1,t);
    tr[k].mx=max(tr[k<<1].mx,tr[k<<1|1].mx);
}
void pushdown(int k)
{
     tr[k<<1].tag+=tr[k].tag;
     tr[k<<1|1].tag+=tr[k].tag;
     tr[k<<1].mx+=tr[k].tag;
     tr[k<<1|1].mx+=tr[k].tag;
     tr[k].tag=0;
}
void update(int k,int a,int b,int x)
{
    int l=tr[k].l,r=tr[k].r;
    if(a==l&&r==b)
    {
        tr[k].tag+=x;
        tr[k].mx+=x;
        return;
    }
    if(tr[k].tag)pushdown(k);
    int mid=(l+r)>>1;
    if(b<=mid)update(k<<1,a,b,x);
    else if(a>mid)update(k<<1|1,a,b,x);
    else
    {
        update(k<<1,a,mid,x);
        update(k<<1|1,mid+1,b,x);
    }
    tr[k].mx=max(tr[k<<1].mx,tr[k<<1|1].mx);
}
int ask(int k,int a,int b)
{
    int l=tr[k].l,r=tr[k].r;
    if(a==l&&b==r){return tr[k].mx;}
    if(tr[k].tag)pushdown(k);
    int mid=(l+r)>>1;
    if(b<=mid)return ask(k<<1,a,b);
    else if(a>mid)return ask(k<<1|1,a,b);
    else return max(ask(k<<1,a,mid),ask(k<<1|1,mid+1,b));
 }
int main(){
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            cin>>ani[i][j];
            sum[i][j]=sum[i][j-1]+ani[i][j];
        }
    for(int i=1;i<=m-k+1;i++)
        dp[1][i]=(sum[1][i+k-1]-sum[1][i-1])+(sum[2][i+k-1]-sum[2][i-1]);
    for(int i=2;i<=n;i++)
    {
        memset(tr,0,sizeof(tr));
        build(1,1,2*m);
        for(int j=1;j<=m;j++)
            update(1,j,j,dp[i-1][j]);
        for(int j=1;j<=k;j++)
            update(1,1,j,-ani[i][j]);
        for(int j=1;j<=m-k+1;j++)
        {
            dp[i][j]=max(dp[i][j],ask(1,1,m)+sum[i][j+k-1]-sum[i][j-1]+sum[i+1][j+k-1]-sum[i+1][j-1]);
            update(1,max(1,j-k+1),j,ani[i][j]);
            update(1,j+1,j+k,-ani[i][j+k]);
        }
    }
    int ans = -1;
    for(int i=1;i<=m;i++)
        ans=max(ans,dp[n][i]);
    cout<<ans<<endl;
}