The Preliminary Contest for ICPC China Nanchang National Invitational and International Silk-Road...

ⅰ亾dé卋堺 提交于 2021-01-13 09:52:06

两个队友链接:

A. PERFECT NUMBER PROBLEM 题库链接

思路:2^1*(2^2-1), 2^2*(2^3-1), 2^4*(2^5-1), 2^6*(2^7-1), 2^12*(2^13-1)

代码:

#include<bits/stdc++.h>
using namespace std;
int main()
{
   cout<<"6\n28\n496\n8128\n33550336\n";
   return 0;
}
View Code

B. Greedy HOUHOU 题库链接

C. Angry FFF Party 题库链接

思路:java大数算,贪心减

代码:

import java.util.*;
import java.math.*;

public class Main {

    /**
     * @param args
     */
    
    static class Matrix {
        BigInteger a[][] = new BigInteger [2][2];
        public void init() {
            for (int i = 0; i < 2; ++i) for (int j = 0; j < 2; ++j) a[i][j] = BigInteger.ZERO;
        }
        public void _init() {
            init();
            for (int i = 0; i < 2; ++i) a[i][i] = BigInteger.ONE;
        }
        public static Matrix mul(Matrix A, Matrix B) {
            Matrix res = new Matrix();
            res.init();
            for (int i = 0; i < 2; ++i) {
                for (int j = 0; j < 2; ++j) {
                    for (int k = 0; k < 2; ++k) {
                        res.a[i][k] = res.a[i][k].add(A.a[i][j].multiply(B.a[j][k]));
                    }
                }
            }
            return res;
        }
        public static Matrix q_pow(Matrix A, BigInteger k) {
            Matrix res = new Matrix();
            res._init();
            while(k.compareTo(BigInteger.ZERO) > 0) {
                if(k.mod(BigInteger.valueOf(2)).compareTo(BigInteger.ZERO) > 0) res = mul(res, A);
                A = mul(A, A);
                k = k.shiftRight(1);
            }
            return res;
        }
        public static BigInteger get_fib(BigInteger n) {
            if(n.compareTo(BigInteger.ONE) == 0) return BigInteger.ONE;
            if(n.compareTo(BigInteger.valueOf(2)) == 0) return BigInteger.ONE;
            Matrix A = new Matrix();
            A.a[1][1] = BigInteger.ZERO;
            A.a[0][0] = A.a[1][0] = A.a[0][1] = BigInteger.ONE;
            A = q_pow(A, n.subtract(BigInteger.valueOf(2)));
            return A.a[0][0].add(A.a[0][1]);
        }
    }
    
    public static BigInteger f[] = new BigInteger[100];
    public static int ans[] = new int[100];
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner in = new Scanner(System.in);
        int T = in.nextInt();
        for (int i = 1; i <= 28; ++i) {
            f[i] = Matrix.get_fib(Matrix.get_fib(BigInteger.valueOf(i)));
        }
        
        while(T > 0) {
            --T;
            BigInteger W = in.nextBigInteger();
            int cnt = 0;
            for (int i = 28; i >= 6; --i) {
                if(f[i].compareTo(W) <= 0) {
                    ans[++cnt] = i;
                    W = W.subtract(f[i]);
                }
            }
            if(W.compareTo(BigInteger.valueOf(1)) == 0) {
                ans[++cnt] = 1;
            }
            else if(W.compareTo(BigInteger.valueOf(2)) == 0){
                ans[++cnt] = 2;
                ans[++cnt] = 1;
            }
            else if(W.compareTo(BigInteger.valueOf(3)) == 0) {
                ans[++cnt] = 3;
                ans[++cnt] = 2;
                ans[++cnt] = 1;
            }
            else if(W.compareTo(BigInteger.valueOf(4)) == 0) {
                ans[++cnt] = 4;
                ans[++cnt] = 2;
                ans[++cnt] = 1;
            }
            else if(W.compareTo(BigInteger.valueOf(5)) == 0) {
                ans[++cnt] = 4;
                ans[++cnt] = 3;
                ans[++cnt] = 2;
                ans[++cnt] = 1;
            }
            else if(W.compareTo(BigInteger.valueOf(6)) == 0) {
                ans[++cnt] = 5;
                ans[++cnt] = 1;
            }
            else if(W.compareTo(BigInteger.valueOf(7)) == 0) {
                ans[++cnt] = 5;
                ans[++cnt] = 2;
                ans[++cnt] = 1;
            }
            else if(W.compareTo(BigInteger.valueOf(8)) == 0) {
                ans[++cnt] = 5;
                ans[++cnt] = 3;
                ans[++cnt] = 2;
                ans[++cnt] = 1;
            }
            else if(W.compareTo(BigInteger.valueOf(9)) == 0) {
                ans[++cnt] = 5;
                ans[++cnt] = 4;
                ans[++cnt] = 2;
                ans[++cnt] = 1;
            }
            else if(W.compareTo(BigInteger.valueOf(10)) == 0) {
                ans[++cnt] = 5;
                ans[++cnt] = 4;
                ans[++cnt] = 3;
                ans[++cnt] = 2;
                ans[++cnt] = 1;
            }
            else if(W.compareTo(BigInteger.valueOf(0)) != 0){
                System.out.println(-1);
                continue;
            }
            for (int i = cnt; i >= 1; --i) {
                System.out.print(ans[i]);
                if(i == 1)System.out.println("");
                else System.out.print(" ");
            }
        }
    }

}
View Code

D. Match Stick Game 题库链接

思路:mx[i][j]:用i根火柴组成一个位数为j的数这个数的最大值 mn[i][j]:用i根火柴组成一个位数为j的数这个数的最小值

dp[i][j]:处理到第i位用了j根火柴式子的最大值

代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include<bits/stdc++.h>
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
//#define mp make_pair
#define pb push_back
#define ULL unsigned LL
#define pll pair<LL, LL>
#define pli pair<LL, int>
#define pii pair<int, int>
#define piii pair<pii, int>
#define pdi pair<double, int>
#define pdd pair<double, double>
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head

const int N = 105, M = 70;
char s[N];
int a[N];
int n, T;
int mx[M][10], mn[M][10];
map<char, int>mp;
int t[10] = {-1, -1, 1, 7, 4, 5, 9, 8};
LL dp[N][705];
void init() {
    for (int i = 1; i < M; ++i) {
        for (int j = 0; j <= 9; ++j) mx[i][j] = INT_MIN, mn[i][j] = INT_MAX;
    }
    mx[0][0] = mn[0][0] = 0;
    for (int i = 1; i <= M; ++i) {
        for (int j = 1; j <= 9; ++j) {
            for (int k = 2; k <= 7 && k <= i; ++k) {
                if(mx[i-k][j-1] != INT_MIN) mx[i][j] = max(mx[i-k][j-1]*10+t[k], mx[i][j]);
                if(mn[i-k][j-1] != INT_MAX) mn[i][j] = min(mn[i-k][j-1]*10+t[k], mn[i][j]);
            }
        }
    }
}
int main() {
    mp['0']=6; mp['1']=2; mp['2']=5; mp['3']=5;
    mp['4']=4; mp['5']=5; mp['6']=6; mp['7']=3;
    mp['8']=7; mp['9']=6; mp['+']=2; mp['-']=1;
    init();
    scanf("%d", &T);
    while(T--) {
        scanf("%d", &n);
        scanf("%s", s);
        int c1 = 1, cnt = 0;
        for (int i = 0; i < n; ++i) {
            if(isdigit(s[i])) cnt += mp[s[i]], a[c1]++;
            else cnt += mp[s[i]], ++c1;
        }
        n = c1;
        for (int i = 0; i <= n; ++i) for (int j = 0; j < 705; ++j) dp[i][j] = LONG_MIN;
        dp[0][0] = 0;
        for (int i = 1; i <= n; ++i) {
            if(i == 1) {
                for (int j = 1; j <= cnt; ++j) {
                    for (int k = 1; k < M && k <= j; ++k) {
                        if(dp[i-1][j-k] != LONG_MIN && mx[k][a[i]] != INT_MIN) dp[i][j] = max(dp[i-1][j-k] + mx[k][a[i]], dp[i][j]);
                    }
                }
            }
            else {
                for (int j = 1; j <= cnt; ++j) {
                    for (int k = 1; k < M; ++k) {
                        if(k+2 <= j && dp[i-1][j-k-2] != LONG_MIN && mx[k][a[i]] != INT_MIN) dp[i][j] = max(dp[i-1][j-k-2] + mx[k][a[i]], dp[i][j]);
                        if(k+1 <= j && dp[i-1][j-k-1] != LONG_MIN && mn[k][a[i]] != INT_MAX) dp[i][j] = max(dp[i-1][j-k-1] - mn[k][a[i]], dp[i][j]);
                    }
                }
            }
        }
        printf("%lld\n", dp[n][cnt]);
        for (int i = 1; i <= n; ++i) a[i] = 0;
    }
    return 0;
}
View Code

E. Card Game 题库链接

F. Information Transmitting 题库链接

G. tsy's number 题库链接 

H. Coloring Game 题库链接

思路:4*3^(n-2)

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int mod=1e9+7;
ll quick(ll x,ll n)
{
    ll ans=1;
    while(n)
    {
        if(n%2==0) { x=x*x%mod; n=n/2; }
        else       {ans=ans*x%mod; n--; }
    }
    return ans;
}
int main()
{
   ll n; cin>>n;
   if(n==1) { cout<<1<<endl; }
   else
   {
       cout<<(quick(2,2)%mod*quick(3,n-2)%mod+mod)%mod<<endl;
   }
   return 0;
}
View Code

 I. Max answer 题库链接

思路:单调栈+区间RMQ

代码:

#include <bits/stdc++.h>

using namespace std;
#define LL long long
#define fi first
#define se second
#define pb push_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
const int N = 5e5 + 5;
int a[N], pre[N], suf[N];
LL sum[N], mx[N<<2], mn[N<<2];
stack<int> st;
int n;
void push_up(int rt) {
    mn[rt] = min(mn[rt<<1], mn[rt<<1|1]);
    mx[rt] = max(mx[rt<<1], mx[rt<<1|1]);
}
void build(int rt, int l, int r) {
    if(l == r) {
        mx[rt] = mn[rt] = sum[l];
        return ;
    }
    int m = l+r >> 1;
    build(ls);
    build(rs);
    push_up(rt);
}
LL querymx(int L, int R, int rt, int l, int r) {
    if(L <= l && r <= R) return mx[rt];
    int m = l+r >> 1;
    LL ans = LONG_MIN;
    if(L <= m) ans = max(ans, querymx(L, R, ls));
    if(R > m) ans = max(ans, querymx(L, R, rs));
    return ans;
}
LL querymn(int L, int R, int rt, int l, int r) {
    if(L <= l && r <= R) return mn[rt];
    int m = l+r >> 1;
    LL ans = LONG_MAX;
    if(L <= m) ans = min(ans, querymn(L, R, ls));
    if(R > m) ans = min(ans, querymn(L, R, rs));
    return ans;
}
int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
    for (int i = 1; i <= n; ++i) sum[i] = sum[i-1] + a[i];
    build(1, 0, n);
    a[0] = a[n+1] = INT_MIN;
    st.push(0);
    for (int i = 1; i <= n; ++i) {
        while(!st.empty() && a[st.top()] >= a[i]) st.pop();
        pre[i] = st.top();
        st.push(i);
    }
    while(!st.empty()) st.pop();
    st.push(n+1);
    for (int i = n; i >= 1; --i) {
        while(!st.empty() && a[st.top()] >= a[i]) st.pop();
        suf[i] = st.top();
        st.push(i);
    }
    LL ans = 0;
    for (int i = 1; i <= n; ++i) {
        int l = pre[i], r = i-1;
        int ll = i, rr = suf[i]-1;
        if(a[i] < 0) {
            ans = max(ans, a[i]*(querymn(ll, rr, 1, 0, n)-querymx(l, r, 1, 0, n)));
        }
        else if(a[i] > 0) {
            ans = max(ans, a[i]*(querymx(ll, rr, 1, 0, n)-querymn(l, r, 1, 0, n)));
        }
    }
    printf("%lld\n", ans);
    return 0;
}
View Code

J. Distance on the tree 题库链接

思路:离线+树剖

代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include<bits/stdc++.h>
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
//#define mp make_pair
#define pb push_back
#define ULL unsigned LL
#define pll pair<LL, LL>
#define pli pair<LL, int>
#define pii pair<int, int>
#define piii pair<pii, int>
#define pdi pair<double, int>
#define pdd pair<double, double>
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head

const int N = 1e5 + 5;
vector<int> g[N];
int fa[N], dp[N], sz[N], son[N], top[N], dfn[N], to[N], cnt = 0, n, m;
int tree[N<<2], ans[N];
struct edge {
    int u, v, w;
    int id;
    bool operator < (const edge & rhs) const {
        return w < rhs.w;
    }
}e[N], q[N];
void push_up(int rt) {
    tree[rt] = tree[rt<<1] + tree[rt<<1|1];
}
void update(int p, int x, int rt, int l, int r) {
    if(l == r) {
        tree[rt] += x;
        return ;
    }
    int m = l+r >> 1;
    if(p <= m) update(p, x, ls);
    else update(p, x, rs);
    push_up(rt);
}
int query(int L, int R, int rt, int l, int r) {
    if(L <= l && r <= R) return tree[rt];
    int m = l+r >> 1;
    int ans = 0;
    if(L <= m) ans += query(L, R, ls);
    if(R > m) ans += query(L, R, rs);
    return ans;
}
void dfs1(int u, int o) {
    fa[u] = o;
    sz[u] = 1;
    dp[u] = dp[o] + 1;
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i];
        if(v != o) {
            dfs1(v, u);
            sz[u] += sz[v];
            if(sz[v] > sz[son[u]]) son[u] = v;
        }
    }
}
void dfs2(int u, int t) {
    top[u] = t;
    dfn[u] = ++cnt;
    to[cnt] = u;
    if(!son[u]) return ;
    dfs2(son[u], t);
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i];
        if(v != fa[u] && v != son[u]) dfs2(v, v);
    }
}
int sum(int u, int v) {
    int ans = 0, fu = top[u], fv = top[v];
    while(fu != fv) {
        if(dp[fu] >= dp[fv]) ans += query(dfn[fu], dfn[u], 1, 1, n), u = fa[fu], fu = top[u];
        else ans += query(dfn[fv], dfn[v], 1, 1, n), v = fa[fv], fv = top[v];
    }
    if(dfn[u] < dfn[v]) ans += query(dfn[u]+1, dfn[v], 1, 1, n);
    else if(dfn[v] < dfn[u]) ans += query(dfn[v]+1, dfn[u], 1, 1, n);
    return ans;
}
int main() {
    scanf("%d %d", &n, &m);
    for (int i = 1; i < n; ++i) {
        scanf("%d %d %d", &e[i].u, &e[i].v, &e[i].w);
        g[e[i].u].pb(e[i].v);
        g[e[i].v].pb(e[i].u);
    }
    dfs1(1, 1);
    dfs2(1, 1);
    for (int i = 1; i <= m; ++i) scanf("%d %d %d", &q[i].u, &q[i].v, &q[i].w), q[i].id = i;
    sort(e+1, e+n);
    sort(q+1, q+1+m);
    int now = 1;
    for (int i = 1; i <= m; ++i) {
        while(now < n && e[now].w <= q[i].w) {
            int u = e[now].u, v = e[now].v;
            if(dp[u] < dp[v]) swap(u, v);
            update(dfn[u], 1, 1, 1, n);
            ++now;
        }
        ans[q[i].id] = sum(q[i].u, q[i].v);
    }
    for (int i = 1; i <= m; ++i) printf("%d\n", ans[i]);
    return 0;
}
View Code

 K. MORE XOR 题库链接

思路:打表找规律+前缀亦或和

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int mod=1e9+7;
const int maxn=1e5+10;
int a[maxn];
int n;
int a1000[maxn];
int a0100[maxn];
int a0010[maxn];
int a0001[maxn];
void make1()
{
    for(int i=1;i<=n;i++)
    {
        if(i%4==1) a1000[i]=a1000[i-1]^a[i];
        else       a1000[i]=a1000[i-1];
    }
    for(int i=1;i<=n;i++)
    {
        if(i%4==2) a0100[i]=a0100[i-1]^a[i];
        else       a0100[i]=a0100[i-1];
    }
    for(int i=1;i<=n;i++)
    {
        if(i%4==3) a0010[i]=a0010[i-1]^a[i];
        else       a0010[i]=a0010[i-1];
    }
    for(int i=1;i<=n;i++)
    {
        if(i%4==0) a0001[i]=a0001[i-1]^a[i];
        else       a0001[i]=a0001[i-1];
    }
}
int work(int l,int r)
{
    int d=r-l+1;
    int ans1=0;
    int ans2=0;

        if(l%4==1)      ans1^=a1000[r]^a1000[l-1];
        else if(l%4==2) ans1^=a0100[r]^a0100[l-1];
        else if(l%4==3) ans1^=a0010[r]^a0010[l-1];
        else            ans1^=a0001[r]^a0001[l-1];

        if(l%4==1)      ans2^=a0100[r]^a0100[l-1];
        else if(l%4==2) ans2^=a0010[r]^a0010[l-1];
        else if(l%4==3) ans2^=a0001[r]^a0001[l-1];
        else            ans2^=a1000[r]^a1000[l-1];
   if(d%4==0)      return 0;
   else if(d%4==1) return ans1;
   else if(d%4==2) return ans1^ans2;
   else            return ans2;

}
int main()
{
int T; scanf("%d",&T);
while(T--)
{
   scanf("%d",&n);
   for(int i=1;i<=n;i++) scanf("%d",&a[i]);  make1();
   int q; scanf("%d",&q);
   while(q--)
   {
      int l,r; scanf("%d %d",&l,&r);
      printf("%d\n",work(l,r));
   }
   for(int i=1;i<=n;i++)
   {
       a0001[i]=0;  a1000[i]=0;a0010[i]=0;a0100[i]=0;
   }
}
return 0;
}
View Code

 L. qiqi'tree 题库链接

思路:暴力计算几何

代码:

#include<bits/stdc++.h>
const double PI=acos(-1.0);
const double TT=PI/3;
using namespace std;
struct Point  { double x,y; Point(){} Point(double x, double y) :x(x), y(y){}  };;
struct Segment{ Point a,b;  Segment(Point x,Point y )     { a=x;b=y; };  Segment(){}; };;
struct Line   { Point a,b;  Line(Point x,Point y )        { a=x;b=y; };  Line(){}; };;
typedef Point Point;
Point operator + (Point A, Point B){ return Point(A.x+B.x, A.y+B.y); } // 向量相加
Point operator - (Point  A, Point  B){ return Point(B.x-A.x, B.y-A.y); } // 向量生成   A-B;
double operator * (Point A, Point B){ return A.x*B.x-A.y*B.y;          } // 点积
double operator ^ (Point A, Point B){ return A.x*B.y-A.y*B.x;          } // 叉积
double Dot(Point A, Point B)   { return A.x*B.x + A.y*B.y; }  // 点积
double Cross(Point A, Point B) { return A.x*B.y-A.y*B.x;   }  // 叉积
double Length(Point A)          { return sqrt(Dot(A, A));   } // 向量长度
double dis(Point a,Point b)      { return sqrt( (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y) ); }
Line qq;
bool check(Segment A,Line B)
{
    Point a=A.a; Point b=A.b;
    Point c=B.a; Point d=B.b;
    if(Cross(a-c,a-d)*Cross(b-c,b-d)>0 ) return 1;
    else return 0;
    return 0;
}
Point make(Segment A,Line B)
{
    Point a=A.a; Point b=A.b;Point c=B.a; Point d=B.b;
    double A1=b.y-a.y,B1=-(b.x-a.x),C1=b.y*a.x-b.x*a.y;
    double A2=d.y-c.y,B2=-(d.x-c.x),C2=d.y*c.x-d.x*c.y;
    double k=A1*B2-A2*B1;
    double x=-(B1*C2-C1*B2)*1.000000000/k;
    double y=(A1*C2-C1*A2)*1.00000000/k;
    Point kk; kk.x=x; kk.y=y;  return kk;
}
double dfs(double l,int k,int d,Point x,double ff)
{
    if(k==d) return 0;
    double ans=0;
    Segment x1;
    x1.a=x;
    x1.b.x=x.x+l*sin(ff); x1.b.y=x.y+l*cos(ff);
    Point W;
    W.x=x.x+l*sin(ff); W.y=x.y+l*cos(ff);
    if(check(x1,qq)==1)
    {
        ans+=l;
        ans+=dfs(l/4,k+1,d,W,ff-TT);
        ans+=dfs(l/4,k+1,d,W,ff);
        ans+=dfs(l/4,k+1,d,W,ff+TT);
    }
    else
    {
        Point P=make(x1,qq); ans+=dis(x,P);
    }
    return ans;
}
void work(double l,int d)
{
    Segment x1;
    x1.a.x=0; x1.a.y=0;
    x1.b.x=0; x1.b.y=l;
    double ans=0;
    Point W;  W.x=0;  W.y=l;
    if(check(x1,qq)==1)
    {
        ans+=l;
        ans+=dfs(l/4,1,d,W,-TT);
        ans+=dfs(l/4,1,d,W,0);
        ans+=dfs(l/4,1,d,W,TT);
    }
    else
    {
        Point x;
        x.x=0;
        x.y=0;
        Point P=make(x1,qq); ans+=dis(x,P);
    }
    cout<<ans<<endl;
}
int main()
{
    cout<<fixed<<setprecision(6);
    int T; cin>>T;
    while(T--)
    {
        int d;
        double l,x1,y1,k; cin>>l>>d>>x1>>y1>>k;
        qq.a.x=x1; qq.a.y=y1;
        qq.b.x=x1+1; qq.b.y=y1+k*1;
        work(l,d);
    }
}
View Code

 M. Subsequence 题库链接

思路:预处理

代码:

#include <bits/stdc++.h>

using namespace std;

#define fi first
#define se second

#define pb push_back

const int inf = 0x3f3f3f3f;
            char str[100009],s1[100009];
            int cnt1[300],cc[300];
            int nxt[100009][30];
            int pt[30];

            int getid(char c) {
                return c - 'a' + 1;
            }
int main(){
            scanf("%s", str);
            int len = strlen(str);
            for(int i=0; i<30; i++) pt[i] = len + 1;
            for(int i=0; i<30; i++) nxt[len+1][i] = len+1;
            for(int i=len-1; i>=0; i--) {
                for(int j=0; j<30; j++)
                    nxt[i][j] = pt[j];
                pt[getid(str[i])] = i;
            }
            int T;  scanf("%d", &T);
            while(T--) {
                scanf("%s", s1);
                int l = strlen(s1);
                int flag = 1,id = pt[getid(s1[0])];

                for(int i=1; i<l; i++) {
                    int d = nxt[id][getid(s1[i])];
                    if(d > id) {
                        id = d;
                    }
                    else {
                        flag = 0;
                        break;
                    }
                }
                if(flag && id <= len) puts("YES");
                else puts("NO");
            }
            return 0;
}
View Code
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!