GYM 101972

题目:

A: Multiplication Dilemma

      我们先把所有数都拆解成 (a+b+c…+d) 的形式,然后利用乘法分配律去掉括号即可.

#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
 
long long a[2][15];
 
int getnum(int x,int num) {
    int len =0;
    int time = 1;
    while(x) {
        if(x%10) {
            a[num][len]=time*(x%10);
            len ++;
        }
        x /=10;
        time *= 10;
    }
    return len;
} 
 
int main() {
    int t;
    scanf("%d",&t);
    while(t--) {
        int c,b;
        scanf("%d%d",&c,&b);
        int len1 = getnum(c,0);
        int len2 = getnum(b,1);
        for(int i=0;i<len1;i++) {
            for(int j=0;j<len2;j++) {
                if(i == 0 && j == 0) printf("%lld x %lld", a[0][i],a[1][j]);
                else printf(" + %lld x %lld",a[0][i],a[1][j]);
            }
        }
        printf("\n");
    }
    return 0;
}

B: Updating the Tree

        对于某点有两个三个或三个以上的分支,不可能构成.
        对于有两个分支的结点,其父亲节点及其祖先也是不能构成的.
        那么现在还剩一个分支,和两个分支的情况.
        很明显我们可以把这两种情况看成是一条链,那么该条链的最小修改次数就等于链上每个数减去一个 自增(减)的标记index 后,链的总长减去权值中出现最多次的次数.
        很明显我们可以搞一个权值线段树,每次查询最大值即可.

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;

const int Pi = 130005;
const int maxn =1e5+7;
const int Maxn = 350050;

int n,e;
int a[maxn];
int head[maxn];
int edge[maxn<<1]; 
int nex[maxn<<1];
int ans[maxn];
int type[maxn];
int sz[maxn];
int tr[2][Maxn<<2];
int lazy[2][Maxn<<2];

void add(int l,int r) {
    edge[++e] = r;
    nex[e]=head[l];
    head[l]=e;
}

void pushdown(int x,int num) {
    if(lazy[x][num]==0) return ;
    lazy[x][num<<1] = lazy[x][num<<1|1] = 1;

    tr[x][num<<1] = tr[x][num<<1|1] = 0;

    lazy[x][num] = 0;
    return ;
}

void pushup(int x,int num) {tr[x][num] = max(tr[x][num<<1],tr[x][num<<1|1]);}

void build(int x,int l,int r,int num) {
    if(l==r) {
        tr[x][num]=0;
        return ;
    }
    int mid = (l+r) >>1;
    build(x,l,mid,num<<1);
    build(x,mid+1,r,num<<1|1);
    pushup(x,num);
}

void modify(int x,int l,int r,int num,int pos,int op) {
    if(op==1) tr[x][num]=0,lazy[x][num]=1;
    if(pos==-1) return ;
    if(pos == l && pos == r) {
        tr[x][num]++;
        return ;
    }
    // printf("%d %d %d\n",l,r,num);
    int mid = (l+r) >>1;
    pushdown(x,num);
    if(pos<=mid) modify(x,l,mid,num<<1,pos,op);
    if(mid< pos) modify(x,mid+1,r,num<<1|1,pos,op);
    pushup(x,num);
}

bool dfs(int u,int f) {
    int sum = 0;
    bool flag=true;
    sz[u] =1;
    for(int i=head[u];i;i=nex[i]) {
        int v = edge[i];
        if(v==f) continue;
        sum++;
        if(!dfs(v,u)) flag=false;
        sz[u]+=sz[v];
    }
    if(flag == true && sum <= 1) type[u]=1;
    else if(!flag || sum >2) type[u]=0;
    else type[u]=2;
    return flag && sum <=1;
}

int index;
int T;

void getans(int u,int f) {
    if(type[u] == 0) ans[u] = -1;
    bool leaf = true;
    if(type[u] == 2) T = u;
    modify(0,1,Maxn,1,a[u]+index+Pi,0);
    modify(1,1,Maxn,1,a[u]-index+Pi,0);
    index++;
            //printf(" %d %d\n",u,index);
    for(int i=head[u];i;i=nex[i]) {
        int v = edge[i];
        if(v==f) continue;
        getans(v,u);
        if(type[u] == 2 && leaf == true) {
            modify(0,1,Maxn,1,a[u]+index+Pi,0);
            modify(1,1,Maxn,1,a[u]-index+Pi,0);
            index++;
        }
        leaf=false;
    }
    if(type[u] != 2 && type[u] != 0) {
        if(!leaf) {
            modify(0,1,Maxn,1,a[u]+index+Pi,0);
            modify(1,1,Maxn,1,a[u]-index+Pi,0);
        }
        if(leaf) {
            ans[T] = max(tr[0][1],tr[1][1]);
            modify(0,1,Maxn,1,-1,1);
            modify(1,1,Maxn,1,-1,1);
            index = 0;
            modify(0,1,Maxn,1,a[u]+index+Pi,0);
            modify(1,1,Maxn,1,a[u]-index+Pi,0);
        }
        ans[u] = max(tr[0][1],tr[1][1]);
        index++;
    }
    else {
        modify(0,1,Maxn,1,-1,1);
        modify(1,1,Maxn,1,-1,1);
    }
    if(T==u) T= 0;
    return ;
}

int main() {
    int t;
    scanf("%d",&t);
    build(0,1,Maxn,1);
    build(1,1,Maxn,1);
    while(t--) {
        e = 0;
        scanf("%d",&n);
        memset(head,0,sizeof(head));
        memset(ans,0,sizeof(ans));
        index = 0;
        T =0;
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        for(int i=0;i<n-1;i++) {
            int l,r;
            scanf("%d%d",&l,&r);
            add(l,r);
            add(r,l);
        }
        dfs(1,0);
        modify(0,1,Maxn,1,-1,1);
        modify(1,1,Maxn,1,-1,1);
        getans(1,0);
        for(int i=1;i<=n;i++){
            printf("%d",ans[i] == -1? -1:sz[i]-ans[i]);
            if(i!=n) printf(" ");
            else printf("\n");
        }
    }
    return 0;
}

C: Shortest Path!

        联想到光的反射,我们每次找对称点就可以了…
        比赛的时候被队友给秒了…

#include <iostream>
#include <algorithm>
#include <cstdio>

using namespace std;

int t;
long double a,b,c,x;

long double getnode(long double x,long double y) {
    return 1.0*(b+c-x)*(a-y) / (b+2*c-x);
}
int main() {
    scanf("%d",&t);
    while(t--) {
        cin>>a>>b>>c>>x;
        long double d =getnode(1.0*0,1.0*0);
        long double ans = (sqrt(d*d+(b+c)*(b+c)) + sqrt((a-d)*(a-d)+c*c));
        long double d2 = getnode(1.0*b*x/100,1.0*a*x/100);
        ans += (sqrt(  1.0*(b+c-1.0*b*x/100)*(b+c-1.0*b*x/100) + d2*d2 )  + sqrt(  c*c  + (a-1.0*a*x/100-d2) *(a-1.0*a*x/100-d2)   ));
        ans += sqrt(1.0*b*b*x*x/10000+1.0*a*a*x*x/10000);
        printf("%.10lf\n",ans);
    }
    return 0;
}

D: Wooden Fence

        签到题.
        直接n,x,y比较即可.

#include <iostream>
#include <algorithm>
#include <cstdio>

using namespace std;

int t;
long long a,b,c;


int main() {
    scanf("%d",&t);
    while(t--) {
        cin>>a>>b>>c;
        b = min(b-1,c);
        if(a>b*2+1) cout<<"NO"<<endl;
        else cout<<"YES"<<endl;
    }
    return 0;
}

E: Stupid Submissions

        看完题目感觉就是说的我没错了
        题目还是直接模拟就可以了,用个int 存当前已经知道了前多少组数据,每次看是不是小数据和已知数据范围内即可.

#include <iostream>
#include <algorithm>
#include <cstdio>

using namespace std;

const int maxn = 1e4+7;

int n,m,k;
int vis[maxn];

int main() {
    int t;
    scanf("%d",&t);
    while(t--) {
        scanf("%d%d%d",&n,&k,&m);
        for(int i=1;i<=n;i++) {
            char s;
            scanf(" %c",&s);
            if(s=='S') vis[i] = 0;
            if(s=='B') vis[i] = 1;
        }
        int ans = 0;
        while(k--) {
            char s;
            scanf(" %c",&s);
            if(s=='W') {
                int d;
                scanf("%d",&d);
                if(d<=m  && vis[d] == 0) ans++;
                m = max(d,m);
            }
            else m = n;
        }
        printf("%d\n",ans);
    }
    return 0;
}

F: I’m Bored!

        分情况讨论.
        最大为 1 的情况.
        最大大于 1 并且没有 1的情况
        最大大于 1 没切 有1的情况
        最大为0的情况

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;

const int maxn = 50;

int ans1=0,ans2=0;
int vis[maxn];

int main() {
    int t;
    scanf("%d",&t);
    while(t--) {
        int flag1 = 1;
        int flag2 = 1;
        memset(vis,0,sizeof(vis));
        for(int i=0;i<26;i++) {
            scanf("%d",&vis[i]);
            if(vis[i]==1) flag1 = 0;
            if(vis[i]>=2) flag2 = 0;
        }
        if(flag2 && flag1) printf("%d %d\n",0,0);
        else if(!flag1 && flag2) {
            int sum = 0;
            for(int i=0;i<26;i++) {
                if(vis[i] != 0) sum++;
            }
            printf("%d %d\n",1,sum);
        }
        else if(!flag2 && flag1) {
            int maxs= 1e9+7;
            int sum1=0,sum2=0;
            for(int i=0;i<26;i++) {
                if(vis[i] == 1) sum2++;
                if(vis[i] >= 2) maxs=min(maxs,vis[i]),sum1++;
            }
            printf("%d %d\n",sum1*2,maxs/2);
        }
        else {
            int maxs= 1e9+7;
            int sum1=0,sum2=0;
            for(int i=0;i<26;i++) {
                if(vis[i] == 1) sum2++;
                if(vis[i] >= 2) maxs=min(maxs,vis[i]),sum1++;
            }
            printf("%d %d\n",sum1*2+1,min(maxs/2,sum2));
        }
    }
    return 0;
}

G: Minimax

        经典的dp,我们先用 O(4 * n * m) 的复杂度求出以上下左右四个顶点为一个顶点的矩阵的最大值.
        然后枚举所有可能的切割交点,更新最大值即可.

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;

int n,m,k;
int a[510][510];
int Max[4][510][510];

int ab(int x,int y) {
    int Maxs=0;
    int Mins=1e9+7;
    Maxs = max(Maxs,Max[0][x-1][y-1]);
    Mins = min(Mins,Max[0][x-1][y-1]);

    Maxs = max(Maxs,Max[1][x-1][y+1]);
    Mins = min(Mins,Max[1][x-1][y+1]);
    
    Maxs = max(Maxs,Max[2][x+1][y-1]);
    Mins = min(Mins,Max[2][x+1][y-1]);
    
    Maxs = max(Maxs,Max[3][x+1][y+1]);
    Mins = min(Mins,Max[3][x+1][y+1]);
    return Maxs - Mins;
}


int main() {
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) {
            for(int j=1;j<=m;j++) {
                scanf("%d",&a[i][j]);
                Max[0][i][j] = a[i][j];
                if(i!=1) Max[0][i][j] = max(Max[0][i][j],Max[0][i-1][j]);
                if(j!=1) Max[0][i][j] = max(Max[0][i][j],Max[0][i][j-1]);
            }
        }
        for(int i=1;i<=n;i++) {
            for(int j=m;j>=1;j--) {
                Max[1][i][j] = a[i][j];
                if(i!=1) Max[1][i][j] = max(Max[1][i][j],Max[1][i-1][j]);
                if(j!=m) Max[1][i][j] = max(Max[1][i][j],Max[1][i][j+1]);
            }
        }
        for(int i=n;i>=1;i--) {
            for(int j=1;j<=m;j++) {
                Max[2][i][j] = a[i][j];
                if(i!=n) Max[2][i][j] = max(Max[2][i][j],Max[2][i+1][j]);
                if(j!=1) Max[2][i][j] = max(Max[2][i][j],Max[2][i][j-1]);
            }
        }
        for(int i=n;i>=1;i--) {
            for(int j=m;j>=1;j--) {
                Max[3][i][j] = a[i][j];
                if(i!=n) Max[3][i][j] = max(Max[3][i][j],Max[3][i+1][j]);
                if(j!=m) Max[3][i][j] = max(Max[3][i][j],Max[3][i][j+1]);
            }
        }
        int ans = 1e9+7;
        for(int i =2;i<n;i++) {
            for(int j=2;j<m;j++) {
                ans = min(ans,ab(i,j));
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

H: Beautiful Substrings

        暴力枚举出所有合理的开头与结尾的组合,然后在第二个字符串里面用后缀和存每个字符出现的次数,暴力搞一下就可以了.

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;

int n,m,k;
char s1[100050];
char s2[100050];
int vis[30][30];
long long pre[30];

long long ans =0;

int main() {
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d%d%s%s",&n,&m,&k,s1,s2);
        memset(vis,0,sizeof(vis));
        memset(pre,0,sizeof(pre));
        ans = 0;
        for(int i=0;i+k-1<n;i++) {
            int d= s1[i]-'a';
            int t = s1[i+k-1]-'a';
            vis[d][t] =1;
        }
        for(int i = m-1;i>=0;i--) {
            int d = s2[i]-'a';
            pre[d]++;
            for(int j=0;j<26;j++) {
                if(vis[d][j] == 0) continue;
                ans += pre[j];
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}

I: Secret Project

        留个坑.
        比赛的时候我的两位神仙队友一个找规律一个证明都搞出了…

J: Even Numbers

        数学题
        留个坑,这种东西一般都交给队友了.

J: Cyclic Shift

        只能挪一位,所以直接模拟就可以了

#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;

string s1,s2;

int main() {
    int t;
    cin>>t;
    while(t--) {
        int n;
        cin>>n;
        cin>>s1>>s2;
        string ss1,ss2;
        int k =0;
        int ls,rs;
        for(int i=0;i<n;i++) {
            if(s1[i] == s2[i]) continue;
            ss1+=s1[i];
            ss2+=s2[i];
        }
        int len=ss1.size();
        if(len == 0) {
            cout<<"YES"<<endl;
            continue;
        }
        if(ss1[0] != ss2[len-1]) cout<<"NO"<<endl;
        else {
            int l=1,r=0;
            for(int i=0;i<len-1;i++) {
                if(ss1[l++] != ss2[r++] ) {
                    cout<<"NO"<<endl;
                    break;
                }
                if(i==len-2) cout<<"YES"<<endl;
            }
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值