T1 string

描述

有一个仅由 '0' 和 '1' 组成的字符串 $A$,可以对其执行下列两个操作:

  • 删除 $A$中的第一个字符;
  • 若 $A$中 '1' 出现的次数为奇数,则在 $A$ 的末尾插入 '1',否则在 $A$ 的末尾插入 '0'.

现在给出一个同样仅由 '0' 和 '1' 组成的字符串 $B$,请你判断 $A$ 能否在任意多次操作后转化为 $B$。

输入

输入文件第一行一个正整数 $T$,表示有 $T$ 组数据需要进行判断。

接下来依次输入 $T$ 组数据,每组数据有两行,其中第一行包含一个字符串 $A$,第二行包含一个字符串 $B$。

输出

输出共 $T$ 行,对应 $T$ 组询问。若第 $i$ 组数据中 $A$串可以转化为 $B$ 串则输出 "YES";否则输出 "NO"。

输入样例 1

输出样例 1

提示

题解

一道水题, 。

自己手推几组样例,就会发现一个规律:ans只与01串中$1$的个数有关

因为你可以讲前面的数删掉加到后面形成组合;

所以如果$A$中$1$的个数大于等于$B$中$1$的个数则输出$YES$,否则输出$NO$;

但是要注意若$A$中$1$的个数为奇数要拿$($$A$中$1$的个数+1$)$与$B$中$1$的个数比较即可;

code:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cctype>
#define ll long long
#define R register
using namespace std;
template<typename T>inline void read(T &a){
    char c=getchar();T x=0,f=1;
    while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    a=f*x;
}
char a[N],b[N];
int lena,lenb,A,B,t;
int main(){
    freopen("string.in","r",stdin);
    freopen("string.out","w",stdout);
    read(t);
    while(t--){
        A=0;B=0;
        scanf("%s%s",(a+1),(b+1));
        lena=strlen(a+1);
        lenb=strlen(b+1);
        for(R int i=1;i<=lena;i++)
            if(a[i]=='1')A++;
        for(R int i=1;i<=lenb;i++)
            if(b[i]=='1')B++;
        if(A&1)A++;
        if(A>=B)printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

T2 glide

描述

大森林中茂盛地生长着 $N$ 棵树,从 $1$ 到 $N$ 编号,第 $i$ 棵树的高度是 $H_i$,住在这片森林里的飞鼠 Makik 可以在树与树之间滑翔。

有 $M$ 组树能供 $Makik$在其间滑翔,在每组树间滑翔的时间是固定的。滑翔时,$Makik$ 每秒会下落 $1$ 米,即当 $Makik$ 当前位置距离地面 $h$ 米时,它经过 $t$ 秒的滑翔后会落到距离地面 $h-t$米的高度上。但若$h-t$ 小于 $0$ 或比要到达的树高还要大,则 $Makik$ 不能进行这次滑行。

除滑翔外,$Makik$ 还可以沿着一棵树爬上爬下,每向上或向下移动 $1$ 米均需花费 $1$ 秒的时间。现在,$Makik$ 想要从第 $1$ 棵树上高度为 $X$ 米的位置移动到第 $N$ 棵树的顶端(高度为 $H_N$ 的位置),请你帮它算一算最少要花费多少秒的时间。

输入

输入文件第一行包含三个整数 $N$,$M$,$X$,分别表示树的数量、能供 $Makik$ 在其间滑翔的树的组数和 $Makik$ 的初始高度。

下面 $N$ 行,其中第 $i$ 行包含一个整数,表示第 $i$ 棵树的高度 $H_i$。

接下来 $M$ 行,其中 $j$ 行包含三个整数 $A_j$,$B_j$,$T_j$($A_j$$\neq$ $B_j$),表示 $Makik$ 可以在第 $A_j$ 棵树和第 $B_j$ 棵树间相互滑行,每次滑行的时间是 $T_j$ 秒。数据保证每一组树都不会被多次给出。

输出

输出一行一个整数,表示 $Makik$ 到达第 $N$ 棵树所至少要花费的秒数。如果不能到达,输出 $-1$。

题解

我这道题在最短路上搞了一些操作,感觉想贪心,感觉不对,;

输入样例 1

输出样例 1

提示

样例说明:

先沿第 $1$ 棵树向上爬 $50$ 米,再依次滑翔到第 $2$ 棵、第 $4$ 棵、第 $5$ 棵树上,最后沿第 $5$ 棵树向上爬 $10$ 米。

数据规模与约定

题解

std讲的思路:

一直跑$SPFA$(或$Dij$堆优化),最后$ans$=(地底下的距离乘以2+地上的距离);

std’s code:
#include <bits/stdc++.h>
using namespace std;

#define N 100005
#define M 600005
#define _inf -4557430888798830400ll

int n, m, h[N];
long long X, d[N];

priority_queue<pair<long long, int> > q;

int head[N];

struct graph
{
    int next, to, val;
    graph() {}
    graph(int _next, int _to, int _val)
    : next(_next), to(_to), val(_val) {}
} edge[M];

inline void add(int x, int y, int z)
{
    static int cnt = 0;
    edge[++cnt] = graph(head[x], y, z);
    head[x] = cnt;
}

void spfa(int s)
{
    memset(d, 0xc0, sizeof d);
    d[s] = X;
    q.push(make_pair(X, s));
    while (!q.empty())
    {
        int x = q.top().second; long long y = q.top().first; q.pop();
        if (y != d[x]) continue;
        for (int i = head[x]; i; i = edge[i].next)
            if (edge[i].val <= h[x])
            if (d[edge[i].to] < min(y - edge[i].val, 1ll * h[edge[i].to]))
                d[edge[i].to] = min(y - edge[i].val, 1ll * h[edge[i].to]),
                q.push(make_pair(d[edge[i].to], edge[i].to));
    }
}

int main()
{
    cin >> n >> m >> X;
    for (int i = 1; i <= n; ++i)
        scanf("%d", &h[i]);
    for (int x, y, z, i = 1; i <= m; ++i)
        scanf("%d%d%d", &x, &y, &z),
        add(x, y, z), add(y, x, z);
    spfa(1);
    if (d[n] == _inf) cout << -1 << endl;
    else cout << (X - d[n]) * 2 - X + h[n] << endl;
    return 0;
}

我的思路:

老师的思路中细节比较少但可能不太好想,但我的写法比较好理解 $(/ω\)$。

我的思路就是在$SPFA$中模拟一个$H$数组,$H_i$表示跑最短路时,在$i$点时的高度(就是你以最短路去走到$i$点时的高度)。

我认为就是在最短路时模拟......(细节比较多)

my code:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cctype>
#include<queue>
#define ll long long
#define R register
#define N 300005
#define INF 0x7fffffffffLL
using namespace std;
template<typename T>inline void read(T &a){
    char c=getchar();T x=0,f=1;
    while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    a=f*x;
}
int n,m,x,head[N],tot,flag,h[N],H[N],vis[N],u,v,w;
ll dist[N];
inline int abss(R int x){return x<0?-x:x;}
struct node{
    int nex,to,dis;
}edge[N<<1];
inline void add(R int u,R int v,R int w){
    edge[++tot].nex=head[u];
    edge[tot].to=v;
    edge[tot].dis=w;
    head[u]=tot;
}
inline void spfa(R int s){
    queue<int>q;
    for(R int i=1;i<=n;i++)dist[i]=INF;
    q.push(s);vis[s]=1;dist[s]=0;H[s]=x;
    while(!q.empty()){
        R int x=q.front();q.pop();vis[x]=0;
        for(R int i=head[x];i;i=edge[i].nex){
            R int xx=edge[i].to;
-------------//下面是模拟判断 细节比较多//--------------------------------------------------------
             R int now=0;//now是模拟你需要爬多少步  正数为向上爬  负数为想下爬
            if(H[x]-edge[i].dis<0)now=(edge[i].dis-H[x]);//以当前高度跳到要更新的点会跳到地下
            else if(H[x]-edge[i].dis>h[xx])now=(-1)*(H[x]-edge[i].dis-h[xx]);//跳到天上
            if(H[x]+now>h[x]||H[x]+now<0)continue;//判断当前能不能爬(不能爬到地下或天上)
            if(dist[xx]>dist[x]+edge[i].dis+abss(now)){
                dist[xx]=dist[x]+edge[i].dis+abss(now);
                H[xx]=H[x]+now-edge[i].dis;// 实时更新H数组
                if(!vis[xx]){
                    vis[xx]=1;
                    q.push(xx);
                }
            }
        }
    }
}
int main(){
    freopen("glide.in","r",stdin);
    freopen("glide.out","w",stdout);
    read(n);read(m);read(x);
    for(R int i=1;i<=n;i++)read(h[i]);
    for(R int i=1;i<=m;i++){
        read(u);read(v);read(w);
        add(u,v,w);add(v,u,w);
    }
    spfa(1);
    if(dist[n]==INF)printf("-1\n");
    else printf("%lld\n",dist[n]+h[n]-H[n]);//因为题中说要爬到第n棵树的树顶
    return 0;
}

未完待续......

10-03 19:49