入门赛8

来源:互联网 发布:微信数据转移到sd卡 编辑:程序博客网 时间:2024/05/19 19:42

  • 前言
  • T1 k-Factorization
    • 题面
    • 题意
    • 思路
    • 代码
    • 小结
  • T2 Odd sum
    • 题面
    • 题意
    • 思路
    • 代码
    • 小结
  • T3 Minimal string
    • 题面
    • 题意
    • 思路
    • WA点
    • 代码
    • 小结
  • T4 Broken BST
    • 题面
    • 题意
    • 思路
    • 代码
    • 小结
  • T5 Array Queries
    • 题面
    • 题意
    • 思路
    • 代码
    • 小结
  • T6 Mice and Holes
    • 题面
    • 题意
    • 思路
    • 代码
    • 小结
  • 总结

前言

比赛,比赛,还是比赛。

本赛涉及题目:
A: [k-Factorization]

B: [Odd sum]

C: [Minimal string]

D: [Broken BST]

E: [Array Queries]

F: [Mice and Holes]


T1 k-Factorization

题面

原题地址: [A]

题意

将n分解成k个数的积,如果不可能输出-1。

思路

质因数分解…

代码

#include<bits/stdc++.h>using namespace std;int main(){    int n,k,a[100],cut=0,i,ans=1;    memset(a,0,sizeof(a));    scanf("%d%d",&n,&k);        for(i=2;i<=n;i++)//分解质因数;    {        if(n%i) continue;        while(n%i==0)        {            a[++a[0]]=i;            n/=i;        }    }    if(a[0]<k) printf("-1");    else    {        for(i=1;i<k;i++) printf("%d ",a[i]);        for(;i<=a[0];i++) ans*=a[i];//将多余的质因数变成一个;        printf("%d",ans);    }    return 0;}

小结

水题*1。


T2 Odd sum

题面

原题地址: [B]

题意

在n个数中删除几个数,使剩下的数的和为奇数且最大。

思路

先正奇偶数都选,如果是奇数,直接输出,否则判断一下最接近0的正奇数与负奇数,选择删还是加(此时只要再删除(加上)一个奇数,和就会变成奇数,删或加由上述两值的abs值决定)。

代码

#include<bits/stdc++.h>#define inf 0x3f3f3f3fusing namespace std;int n,x,i,ans,a[1000000],cut,maxn,minn,sum;bool cmp(int x,int y){ return x>y; }int main(){    maxn=-inf;    minn=inf;    for(scanf("%d",&n),i=0;i<n;i++)    {        scanf("%d",&x);        if(x>0) sum+=x;        if(x&1&&x<0&&x>maxn) maxn=x;        if(x&1&&x>0&&x<minn) minn=x;    }    sum&1?printf("%d",sum):printf("%d",max(sum-minn,sum+maxn));    return 0;}

小结

水题*2。


T3 Minimal string

题面

原题地址: [C]

题意

将一个字符串通过入栈出栈的操作,使出栈后得到的字符串字典序最小。

思路

贪心…

WA点

将当前最优字母出栈后,还要在判断栈顶字母,是不是还是最优,而不是直接再入栈。

代码

#include<bits/stdc++.h>using namespace std;stack<char> t;queue<char> s;map<char,int> num;char ch='a',c;bool p;int main(){    num[char('z'+1)]=1;    while(~scanf("%c",&c)&&c!='\n') s.push(c),num[c]++;    while(num[ch]==0) ch++;    while(!s.empty())    {        t.push(s.front());        s.pop();        num[t.top()]--;        p=false;        while(!t.empty())//这一段while是重点,回判栈顶;        {            for(c=t.top()-1;c>='a';c--) if(num[c]) p=true;            if(p) break;            printf("%c",t.top());//贪心:当前最优出栈;            t.pop();        }    }    while(!t.empty()) printf("%c",t.top()),t.pop();    return 0;}

小结

水题*3,不过很可惜我在WA点WA了n次~~(STL自己研究)


T4 Broken BST

题面

原题地址: [D]

题意

给每个点的权值,左右孩子,问用BST搜索法有几个数搜索不到。搜索的数为每一个点的权值。
(权值可以重复,一个权值k被搜到了,其他的相等权值k都当可以搜到)。

思路

如果点i的权值k无法搜到,而点p的权值k可以搜到,还是算k可以搜到(两个k都算可以搜到),所以只用把所有可以搜到的数拉出来,剩下是就是不可搜到的。
这个数如果比它到根节点的所有向右的权值的maxn大,所有向左的minn小,这个数就是可以搜到的(不包括这个点的权值)。

代码

#include<bits/stdc++.h>#define N 100000#define inf 0x3f3f3f3fusing namespace std;struct Tree{    int num,l,r;}tr[N+5];bool p[N+5];int n,i,ans;map<int,int> m;map<int,int>::iterator it;void dfs(int i,int maxn,int minn){    if(i==-1) return;    if(tr[i].num>=maxn&&tr[i].num<=minn) m[tr[i].num]=0;//可以搜到,这个数(包括其他点的相等权值)就不是不能搜到的点;    dfs(tr[i].l,maxn,min(minn,tr[i].num));//向左更新minn;    dfs(tr[i].r,max(maxn,tr[i].num),minn);//向右更新maxn;}int main(){    m.clear();    memset(p,true,sizeof(p));    for(scanf("%d",&n),i=1;i<=n;i++)    {        scanf("%d%d%d",&tr[i].num,&tr[i].l,&tr[i].r);        if(tr[i].l!=-1) p[tr[i].l]=false;//找出根节点;        if(tr[i].r!=-1) p[tr[i].r]=false;        m[tr[i].num]++;//出现的数;    }i=1;    while(!p[i]) i++;    dfs(i,-inf,inf);//搜索;    for(it=m.begin();it!=m.end();it++)//寻找有多少个点没被搜到;    {        ans+=it->second;    }    printf("%d",ans);    return 0;}

小结

权值有重复,一个可以搜到就算全部可以搜到,这一点是重点!!


T5 Array Queries

题面

原题地址: [E]

题意

有n个数和m个询问,p在经过多少次操作之后会>n。
操作:p=p+a[p]+k。

思路

由于p可以从后往前推,所以DP是可以的,而题意也让人想到了模拟,但因为数据范围,DP->MLE,模拟->TLE,所以使用分治,k<=sqrt(n)时DP,其余的用模拟。
原理:k小时,模拟的次数较多,易超时,所以用O(n)的DP预处理。

代码

#include<bits/stdc++.h>using namespace std;int ans,a[100005][351],p,k,n,m,i,j;int main(){    for(scanf("%d",&n),i=1;i<=n;i++) scanf("%d",&a[i][0]);    for(j=1;j<=350;j++)//k<=350时DP;    {        for(i=n;i>=1;i--)        {            a[i][0]+i+j>n?a[i][j]=1:a[i][j]=a[a[i][0]+i+j][j]+1;        }    }    for(scanf("%d",&m),i=1;i<=m;i++)    {        scanf("%d%d",&p,&k);        if(k<=350) printf("%d\n",a[p][k]);        else//其余模拟;        {            ans=0;            while(a[p][0]+p+k<=n)            {                p=a[p][0]+p+k;                ans++;            }            printf("%d\n",ans+1);        }    }    return 0;}

小结

水是水,但不知多久没打分治了,差点没想起这种算法。


T6 Mice and Holes

题面

原题地址: [F]

题意

有n之老鼠,m个洞,每个洞都有其容量上限,问所有老鼠进洞所需的最小距离和。

思路

设dp[i][j]表示前i个洞进了j只老鼠的最小距离和,易知dp[i][j]=min(dp[i][j],dp[i-1][k]+sum[i][j]-sum[i-1][k]),0<=k<=j。显然我们暴搜的复杂度为n*m*k,但我们知道,sum[i][k]会被多次枚举,而且dp[i][j],是一个定值,所以我们只要知道sum[i][k]的区间最大值就行了,此时我们可以用单调队列来优化区间多次求最大值。
(好吧,我承认我不会讲)

代码

#include<bits/stdc++.h>#define LL long long#define inf 0x3f3f3f3f#define N 5000using namespace std;pair<LL,LL> hole[N+5];LL mice[N+5],sum[N+5],pre[N+5],dp[N+5][N+5],que[N+5],n,m,i,j,l,r;int main(){    for(scanf("%d%d",&n,&m),i=1;i<=n;i++) scanf("%lld",&mice[i]);    for(i=1;i<=m;i++) scanf("%lld%lld",&hole[i].first,&hole[i].second);    sort(mice+1,mice+n+1),sort(hole+1,hole+m+1);memset(dp,inf,sizeof(dp));    for(i=1;i<=m;i++) pre[i]=pre[i-1]+hole[i].second;    if(pre[m]<n) return 0*puts("-1");    for(dp[0][0]=0,i=1;i<=m;i++)    {        dp[i][0]=l=r=que[++r]=0;        for(j=1;j<=pre[i]&&j<=n;j++)        {            dp[i][j]=dp[i-1][j];que[++r]=j;            sum[j]=sum[j-1]+llabs(mice[j]-hole[i].first);            while(j-que[l]>hole[i].second) l++;            while(l<r&&dp[i-1][que[l]]-sum[que[l]]>dp[i-1][j]-sum[j]) l++;            dp[i][j]=min(dp[i][j],sum[j]+dp[i-1][que[l]]-sum[que[l]]);        }    }    printf("%lld\n",dp[m][n]);}

小结

单调队列不会,状态转移方程不会,什么都不会!!!


总结

每一题都WA在莫名其妙的地方,搞得我超级慌~~

原创粉丝点击