2019徐州网络赛题解

比赛地址

计蒜客

[A]Who is better?

题意

给定一个同余方程组,求其最小整数解.然后根据这个解进行一个博弈游戏.设解为n,则有n个石子.双方轮流取石子,第一次至少取1个石子,但不能拿完.设第i次取了x个,则i+1次只能取1~2x个.谁取走最后一个石子谁赢.求先手必胜还是必负.

题解

先拿广义中国剩余定理求解,得到n.然后暴力打表找规律,发现当n是斐波那契数的时候,后手必胜.

代码

#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
#include<cmath>
#define N 15
#define l(x) (x<<1)
#define r(x) ((x<<1)+1)
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;

int i,k;
int a[5];
LL n,low,high,mid,ss;
LL p[N],r[N],f[10010];

inline LL Abs(LL x){return (x<0)?-x:x;}
inline void Swap(LL &a,LL &b){a^=b^=a^=b;}
inline LL Min(LL a,LL b){return (a<b)?a:b;}
inline LL Max(LL a,LL b){return (a>b)?a:b;}

inline int read(){
    int p=0;    char    c=getchar();
    while (c<48||c>57)  c=getchar();
    while (c>=48&&c<=57)    p=(p<<1)+(p<<3)+c-48,c=getchar();
    return p;
}

inline LL Gcd(LL a,LL b){return (!b)?a:Gcd(b,a%b);}

inline void Ex_gcd(LL a,LL b,LL &x,LL &y){
    LL p=0,q=0;
    if (b==0) {
        x=1;    y=0;    return;
    }   else {
        Ex_gcd(b,a%b,p,q);
        x=q;    y=p-a/b*q;
    }
}

inline LL Solve(){
    int i=0;
    LL a=0,b=0,c=0,gcd=0,k1=0,k2=0;
    for (i=1;i<k;i++){
        a=p[i]; b=p[i+1];   c=r[i+1]-r[i];
        gcd=Gcd(a,b);
        if (c%gcd)  return -1;
        a/=gcd; b/=gcd; c/=gcd;
        Ex_gcd(a,b,k1,k2);
        k1=((k1*c)%b+b)%b;
        p[i+1]=p[i]/gcd*p[i+1];
        r[i+1]=(k1*p[i]%p[i+1]+r[i])%p[i+1];
    }
    return r[k];
}

int main(){
    scanf("%d",&k);
    for (i=1;i<=k;i++)
        scanf("%lld%lld",&p[i],&r[i]);
    n=Solve();
    if (n==-1){
        cout<<"Tankernb!";
        return 0;
    }
    f[1]=1; f[2]=2;
    for (i=3;i<=72;i++)
        f[i]=f[i-1]+f[i-2];
    for (i=1;i<=72;i++){
        if (n==f[i]){
            cout<<"Lbnb!"<<endl;
            return 0;
        }
    }
    cout<<"Zgxnb!"<<endl;
    return 0;
}

比赛的时候读错题了啊啊啊,表都打出来一个了,虽然是错的...差点就A了

[B]So easy

题意

给出长度为n的一个列表,有m个操作.第一种操作是把列表的x位置置为不可用,第二种操作是询问x位置后面第一个可用的位置是什么(包括自己).对于所有的询问操作,输出答案.

题解

考虑使用并查集维护联通关系.每次遇到置为不可用的操作,就把x位置前后的两个元素中的不可用元素和x合并,同时记录集合的大小,也就是连续的不可用区间的长度.对于所有的询问操作,先检查后面相邻的元素是否可用,如果不可用,就可以根据集合大小找到第一个可用元素.

因为数据规模较大所以需要拿map离散一下.(第一次用unordered_map,听说插入和询问都是O(1)的,新技能get,只是在判断是否为空的时候需要借助特殊的函数)

代码

#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
#include<cmath>
#include<unordered_map>
#define l(x) (x<<1)
#define r(x) ((x<<1)+1)
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;

int n,m,i,x,y,fa,z;

unordered_map <int,int> f,v,size;

inline int Abs(int x){return (x<0)?-x:x;}
inline void Swap(int &a,int &b){a^=b^=a^=b;}
inline int Min(int a,int b){return (a<b)?a:b;}
inline int Max(int a,int b){return (a>b)?a:b;}

namespace IO{
    char buf[1<<15],*fs,*ft;
    inline char gc(){return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;}
    inline int gint(){
        int x=0,ch=gc();
        while(ch<'0'||ch>'9') ch=gc();
        while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=gc();
        return x;
    }
}
using namespace IO;

inline int Find(int x){return (f[x]==x)?x:f[x]=Find(f[x]);}

int main(){
    n=gint();   m=gint();
    for (i=1;i<=m;i++){
        x=gint();   y=gint();
        if (x==2&&y==n){
            if (v.count(y)) puts("-1");
            else printf("%d\n",y);
            continue;
        }
        if (x==1){
            if (v.count(y)) continue;
            v[y]=1; z=f[y]=y;   size[y]=1;
            if (y+1<=n&&v.count(y+1)){
                fa=Find(f[y+1]);
                f[fa]=z;    size[z]+=size[fa];
            }
            if (y-1&&v.count(y-1)){
                fa=Find(f[y-1]);
                f[z]=fa;    size[fa]+=size[z];
            }
            continue;
        }
        if (!v.count(y))    {printf("%d\n",y);  continue;}
        if (!v.count(y+1))  {printf("%d\n",y+1);    continue;}
        else {
            fa=Find(y+1);
            fa=fa+size[fa];
            if (fa<=n)  printf("%d\n",fa);
            else puts("-1");
        }
    }
    return 0;
}

[C]Buy Watermelon

题意

给定一个数n,判断能不能把n分成两部分,使得每一部分都是2的倍数.

题解

签到题

代码

#include <stdio.h>
int main()
{
    int n;
    scanf("%d", &n);
    if(n%2==0&&n!=2)
        puts("YES");
    else
        puts("NO");
    return 0;
}

[D]Carneginon

题意

给定一个串,然后有m次询问,每次会再次给定一个串,判断短一点的那个串是不是长串的子串.如果长度相同,就判断是不是相等.

题解

考虑到题目中有

m(|S|+|T|)\leq 1e7

所以直接套KMP即可.长度相等就暴力判断.

代码

#include <cstdio>
#include <cstring>

constexpr int MQ(2e3+6);
constexpr int ML(2e5+6);
constexpr int MN(5e6+5);
constexpr int MA(26);


char len_cmp[MQ];
bool has[MQ];
bool belong[MQ];
bool eq[MQ];

struct KMPer
{
    char *str;
    int len;
    int next[ML];

    int get_next(char *s, int l)
    {
        len = l, str = s;
        int i = 0, j = next[0] = -1;
        while (i < len)
        {
            if (j==-1 || s[i]==s[j]) 
                next[++i] = ++j;
            else
                j = next[j];
        }

        return len;
    }
    void get_next_t(char *p, int l)
    {
        str = p;
        len = l;
        int t1 = 0, t2;
        next[0] = t2 = -1;
        while (t1 < l) 
            if (t2==-1 || p[t1]==p[t2])
                next[++t1] = ++t2;
            else t2 = next[t2];
    }
    bool kmp(char *p, int l)
    {
        int t1=0, t2=0;
        while (t1 < l)
        {
            if (t2==-1 || p[t1]==str[t2])
                t1++, t2++;
            else t2 = next[t2]; 
            if (t2 == len)
                return true;
        }
        return false;
    }
} ker;

char t[ML], s[ML];

int main()
{
    int n;
    scanf("%s %d", t, &n);
    int len_t = strlen(t);
    for (int i=1; i<=n; ++i)
    {
        scanf("%s", s);
        int len_s = strlen(s);
        if (len_s > len_t)
        {
            len_cmp[i] = 1;
            ker.get_next(t, len_t);
            belong[i] = ker.kmp(s, len_s);
        }
        else if (len_s < len_t)
        {
            len_cmp[i] = -1;
            ker.get_next(s, len_s);
            has[i] = ker.kmp(t, len_t);
        }
        else
        {
            len_cmp[i] = 0;
            eq[i] = !strcmp(s, t);
        }
    }

    for (int i=1; i<=n; ++i)
    {
        if (len_cmp[i] == 1)    // len_s > len_t
        {
            puts(belong[i] ? "my teacher!" : "senior!");
        }
        else if (len_cmp[i] == -1)
        {
            puts(has[i] ? "my child!" : "oh, child!");
        }
        else
        {
            puts(eq[i] ? "jntm!" : "friend!");
        }
    }

    return 0;
}

[E]XKC's basketball team

题意

CXK有一个篮球队,编号1~n.每个人有一个能力值,对于第i个人,设其能力值为w.如果存在一个编号比他大而且能力值不小于w+m的人,他就会angry.求对于每个人,让他angry的人中距离他最远的人有多远.距离的定义是两人之间的其他人的数量.如果没有输出-1.

题解

按照能力值排序.以排序后各个元素的原始位置作为权值,用ZKW线段树维护区间最大值.然后对第i个人二分出数列中不小于w+m的最小序号.然后在ZKW线段树上查询.如果编号小于i则输出-1,否则直接输出答案.

代码

#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
#include<cmath>
#define N 500010
#define l(x) (x<<1)
#define r(x) ((x<<1)+1)
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;

int n,m,i;
int b[N],c[N],Ans[N];
int f[N][22];

struct Data{
    int x,y;
    bool operator <(const Data &o) const{
        return y<o.y;
    }
    bool operator >(const Data &o) const{
        return y>o.y;
    }
}a[N];

inline bool cmp(const Data &c,const Data &b){return c.x<b.x;}

inline int Abs(int x){return (x<0)?-x:x;}
inline void Swap(int &a,int &b){a^=b^=a^=b;}
inline int Min(int a,int b){return (a<b)?a:b;}
inline int Max(int a,int b){return (a>b)?a:b;}

template <typename sint, typename xint = int>
class ZKW
{
private:

    sint t[N << 2];
    xint n, _offset;    // 必须要有offset
#define _getl(l) l-_offset
#define _getr(r) r+1-_offset

#define li i<<1
#define ri i<<1|1
#define pu(i) \
    ({ \
        t[i] = t[li]>t[ri]?t[li]:t[ri]; \
    })

public:

    void build(const sint *arr, const xint l, const xint r) // 注意arr也是sint*类型!否则下面memcpy就不匹配了
    {
        _offset = l;    // [l, r] -> [0, n), 则_getl(l)==l-_offset==0, 则_offset==l; _getl(r)==r+1-_offset==n, 也能推出_offset==l。
        n = r-l+1;

        memcpy(t+n, arr+l, sizeof(sint) * n);
        for (int i=n-1; i; --i)
            pu(i);
    }

    void add(xint p, const sint v)
    {
        for (t[p=_getl(p)+n]+=v; p>1; p>>=1)
            t[p>>1] = t[p] + t[p^1];
    }

    sint max(xint l, xint r)
    {
        sint maxv = (Data){-1,-1}, tpp;
        for (l=_getl(l)+n, r=_getr(r)+n; l<r; l>>=1, r>>=1)
        {
            if (l&1)
            {
                tpp = t[l++];
                if (tpp > maxv)
                    maxv = tpp;
            }

            if (r&1)
            {
                tpp = t[--r];
                if (tpp > maxv)
                    maxv = tpp;
            }
        }
        return maxv;
    }
};

ZKW <Data> T;

inline int read(){
    int p=0;    char    c=getchar();
    while (c<48||c>57)  c=getchar();
    while (c>=48&&c<=57)    p=(p<<1)+(p<<3)+c-48,c=getchar();
    return p;
}

inline void Ready(){
    int i=0;
    T.build(a,1,n);
    for (i=1;i<=n;i++)  c[i]=a[i].x;
}

inline bool Check(int x,int y){
    return a[x].x>=y;
}

inline int Query(int x,int y){
    return T.max(x,y).y;
}

inline int Find(int x){
    return lower_bound(c+1, c+n+1, x) - c;
}

inline void Work(){
    int i=0,low=1,high=n,mid=0,ans=0;
    for (i=1;i<=n;i++){
        ans=Find(b[i]+m);
        if (ans>n){
            Ans[i]=-1;  continue;
        }
        ans=Query(ans,n);
        if (ans<i)  Ans[i]=-1;  else Ans[i]=ans-i-1;
    }
    for (i=1;i<n;i++)   printf("%d ",Ans[i]);
    printf("%d",Ans[n]);
}

int main(){
    n=read();   m=read();
    for (i=1;i<=n;i++){
        a[i].x=read();  a[i].y=i;
        b[i]=a[i].x;
    }
    sort(a+1,a+1+n,cmp);
    Ready();    Work();
    return 0;
}

[G]Colorful String

题意

对于每一个回文串,定义其价值是所含有的不同字母的数量.然后给定一个字符串,求其所有回文子串的价值总和.

题解

先跑一遍Manachar.然后对于每一个位置,预处理出26个字母的第一次出现的位置.对于每一个回文中心,先计算出回文半径,然后枚举26个字母,检查是否落在了半径之内.如果是,则算一下对答案的贡献.

代码

#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
#include<cmath>
#define N 300010
#define l(x) (x<<1)
#define r(x) ((x<<1)+1)
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;

int n,cnt;
char c[N],C[N*2];
int p[N*2],h[N*2][26];
LL Ans;

inline int Abs(int x){return (x<0)?-x:x;}
inline void Swap(int &a,int &b){a^=b^=a^=b;}
inline int Min(int a,int b){return (a<b)?a:b;}
inline int Max(int a,int b){return (a>b)?a:b;}

inline int read(){
    int p=0;    char    c=getchar();
    while (c<48||c>57)  c=getchar();
    while (c>=48&&c<=57)    p=(p<<1)+(p<<3)+c-48,c=getchar();
    return p;
}

inline void Manachar(){
    int i=0,mx=0,id=0;
    for (i=2;i<cnt;i++){
            if (i<mx)   p[i]=Min(p[2*id-i],mx-i);   else p[i]=1;
            while (C[i+p[i]]==C[i-p[i]])    p[i]++;
            if (i+p[i]>mx)  mx=i+p[i],id=i;
    }
}

inline void Ready(){
    int i=0,j=0,p=-1;
    for (i=0;i<n;i++){
        C[++cnt]='#';   C[++cnt]=c[i];
    }
    C[++cnt]='%';
    for (i=0;i<=25;i++){
        p=-1;
        for (j=cnt;j;j--){
            if (C[j]-'a'==i)    p=j;
            h[j][i]=p;
        }
    }
    Manachar();
}

inline void Work(){
    int i=0,j=0,r=0,x=0;
    for (i=1;i<cnt;i++){
        r=p[i];
        if (C[i]!='#')  r=(r+1)/2;
        else r=r/2;
        if (!r) continue;
//      cout<<C[i]<<" "<<r<<endl;
        for (j=0;j<=25;j++){
            x=h[i][j];
            if (x==-1)  continue;
            if (C[i]!='#')  {
                x=(x-i)/2+1;
                if (x<=r){
                    Ans+=(LL)(r-x+1);
//                  cout<<C[i]<<" "<<r<<" "<<j<<" "<<x<<endl;
                }
            }   else {
                x=(x-i+1)/2;
                if (x<=r)   {
//                  cout<<C[i]<<" "<<r<<" "<<j<<" "<<x<<endl;
                    Ans+=(LL)(r-x+1);
                }
            }
        }
    }
//  for (i=1;i<=cnt;i++)    cout<<i<<" "<<p[i]<<endl;
    cout<<Ans<<endl;
}

int main(){
    scanf("%s",&c);
    n=strlen(c);
    Ready();    Work();
    //cout<<h[4][1]<<endl;
    return 0;
}

[J]

题意

给出一棵树和一段伪代码.求程序按照伪代码运行时求出正确树高的概率.

伪代码的内容为:把Dfs时选择子节点的过程改为随机选取.

题解

树形dp.

设dp[x]表示选择x节点后得到正确树高的概率.然后跑树形dp.注意要先求出进行一次选择后,求出正确树高的概率.然后反向算出在一定次数的选择后不能求出树高的概率,再拿1减去上面的结果即可.

代码

#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
#include<cmath>
#define N 1000010
#define MOD 1000000007ll
#define l(x) (x<<1)
#define r(x) ((x<<1)+1)
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;

int n,i,lsum=1,dep,x,y;
int d[N],v[N],head[N];
LL inv[N],dp[N];

struct Flow{
    int t,next;
}e[N*4];

inline int Max(int a,int b){return (a>b)?a:b;}

inline void Add(int s,int t){
    e[lsum].t=t;    e[lsum].next=head[s];   head[s]=lsum++;
}

inline void Ready(){
    LL i=0;
    inv[1]=1;
    for (i=2;i<=1000000;i++)
        inv[i]=inv[MOD%i]*(MOD-MOD/i)%MOD;
}

inline LL Mi(LL x,LL y){
    LL p=x,t=1,Res=1;
    for (;t<=y;(t&y)?Res=(Res*p)%MOD:0,p=(p*p)%MOD,t<<=1);
    return Res;
}

inline void Make(int x){
    int i=0;
    dep=Max(dep,d[x]);
    for (i=head[x];i;i=e[i].next)
        if (!d[e[i].t]){
            d[e[i].t]=d[x]+1;   Make(e[i].t);
        }
}

inline void Dfs(int x){
    int i=0;
    LL tot=0,p=0,s=0,sum=0;
    dp[x]=0;
    if (d[x]==dep){dp[x]=v[x]=1;    return;}
    for (i=head[x];i;i=e[i].next){
        if (d[e[i].t]<d[x]) continue;
        tot++;  Dfs(e[i].t);
        if (v[e[i].t])  v[x]=1,sum+=dp[e[i].t];
    }
    if (!v[x])  {dp[x]=0;   return;}
    sum=(sum*inv[tot])%MOD;
    s=(1-sum+MOD)%MOD;
    s=Mi(s,tot);
    dp[x]=(1-s+MOD)%MOD;
}

int main(){
    scanf("%d",&n);
    Ready();
    for (i=1;i<n;i++){
        scanf("%d%d",&x,&y);
        Add(x,y);   Add(y,x);
    }
    d[1]=1; Make(1);    Dfs(1);
    cout<<dp[1]<<endl;
    return 0;
}

[K]Center

题意

给定n个点,求出最少需要补上几个点(位置任意),可以使得所有的点构成一个中心对称图形.

题解

考虑到要使补充的点的数量最少,就要尽可能在原来的点中找出尽可能多的对称点对.所以暴力枚举所有的二元点对,计算其对称中心,扔到map里离散化一下.然后统计出每个对称中心最多能够利用多少个点.答案就是点数减去最多利用的点数.

对于重点的情况要特殊处理.

代码

#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
#include<cmath>
#include<map>
#define N 1010
#define l(x) (x<<1)
#define r(x) ((x<<1)+1)
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;

int n,i,cnt,Ans;

struct Data{
    int x,y,z;
    bool operator <(const Data &b) const{
        return (x==b.x)?y<b.y:x<b.x;
    }
}a[N],b[N];

map <Data,int> M;

inline int Abs(int x){return (x<0)?-x:x;}
inline void Swap(int &a,int &b){a^=b^=a^=b;}
inline int Min(int a,int b){return (a<b)?a:b;}
inline int Max(int a,int b){return (a>b)?a:b;}

inline bool cmp(const Data &a,const Data &b){return (a.x==b.x)?a.y<b.y:a.x<b.x;}

inline int read(){
    int p=0;    char    c=getchar();
    while (c<48||c>57)  c=getchar();
    while (c>=48&&c<=57)    p=(p<<1)+(p<<3)+c-48,c=getchar();
    return p;
}

inline void Work(){
    int i=0,j=0;
    Data p;
    for (i=1;i<=cnt;i++)
        for (j=i+1;j<=cnt;j++){
            p.x=(b[i].x+b[j].x)/2;
            p.y=(b[i].y+b[j].y)/2;
            M[p]+=b[i].z+b[j].z;
            if (M[p]>Ans)   Ans=M[p];
        }
    for (i=1;i<=cnt;i++){
        p.x=b[i].x; p.y=b[i].y;
        M[p]+=b[i].z;
        if (M[p]>Ans)   Ans=M[p];
    }
    cout<<n-Ans<<endl;
}

int main(){
    scanf("%d",&n);
    for (i=1;i<=n;i++){
        scanf("%d%d",&a[i].x,&a[i].y);
        a[i].x*=2;  a[i].y*=2;  
    }
    sort(a+1,a+1+n);
    a[0].x=-5689;   a[0].y=-599;
    for (i=1;i<=n;i++){
        if (a[i].x==a[i-1].x&&a[i].y==a[i-1].y){
            b[cnt].z++; continue;
        }
        cnt++;
        b[cnt]=a[i];    b[cnt].z++;
    }
    if (cnt==1){
        cout<<"0"<<endl;
        return 0;
    }
    Work();
    return 0;
}

[M]Longest subsequence

题意

给出两个字符串T和S.求T中的最长子序列L,使得L的字典序严格大于S.如果无解,输出-1.

题解

设S开头的字母为c.首先考虑L点的开头字母p.如果p的字典序大于c,则可以取位置最靠前的p,然后一直到结尾构成的子序列即为L.当p的字典序等于c时,考虑一位一位枚举L的字母,然后在T中进行跳转选取子序列.这时需要预处理对于每一个位置,26个字母的第一次出现的位置.每次选择字母时,均贪心选择最靠前的那个字母.正确性显然.

设接下来该匹配到了S的第x位,原串T选择到了第y位.此时无非有两种选择:字典序大于S或者等于S.当无法选择字母使得字典序不小于S时,该情况无解.如果选择大于x的字典序,则依次枚举大于S当前位置的字母,求y位置后最靠前的这些字母,统计答案,然后结束这一过程.或者选择字典序相等的字母,利用预处理的结果跳转y.最后统计答案即可.

具体细节见代码.

代码

#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
#include<cmath>
#define N 1000010
#define l(x) (x<<1)
#define r(x) ((x<<1)+1)
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;

int n,m,i,j,x,Ans,y;
int h[50],w[50],f[N][26];
char c[N],s[N];

inline int Abs(int x){return (x<0)?-x:x;}
inline void Swap(int &a,int &b){a^=b^=a^=b;}
inline int Min(int a,int b){return (a<b)?a:b;}
inline int Max(int a,int b){return (a>b)?a:b;}

inline int read(){
    int p=0;    char    c=getchar();
    while (c>=48&&c<=57)    p=(p<<1)+(p<<3)+c-48,c=getchar();
    return p;
}

int main(){
    scanf("%d%d",&n,&m);
    scanf("%s",c+1);
    scanf("%s",s+1);
    for (i=0;i<=25;i++) w[i]=-1;
    for (i=n;i;i--){
        for (j=0;j<=25;j++) f[i][j]=w[j];
        x=c[i]-'a'; h[x]=i;
        w[c[i]-'a']=i;
    }
    Ans=-1;
    for (i=s[1]-'a'+1;i<=25;i++)
        if (h[i])   Ans=Max(Ans,n-h[i]+1);
//  cout<<Ans<<endl;


    if (Ans==-1&&h[s[1]-'a']==0){
        cout<<"-1"<<endl;
        return 0;
    }

    x=1;    y=h[s[1]-'a'];
    while (x<m&&y>0){
        x++;
        for (i=s[x]-'a'+1;i<=25;i++)
            if (f[y][i]>0)
                Ans=Max(Ans,x-1+n-f[y][i]+1);
        y=f[y][s[x]-'a'];
    }
    //cout<<y<<endl;
    if (y==n)   {
        printf("%d\n",Ans);
        return 0;
    }
    if (y>0)    Ans=Max(m+n-y,Ans);
    cout<<Ans<<endl;
    return 0;
}
说点什么
支持Markdown语法
好耶,沙发还空着ヾ(≧▽≦*)o
Loading...