【题解】牛客NOIP暑期七天营-普及组3

X操作
100分以下做法:我也不知道怎么写
100分做法:
首先,判断的第一条件是m>=abs(x-y),表示操作次数大于两数的差,因为如果操作次数小于两数的差了,那么x一定时无法变成y的,其次,如果操作abs(x-y)次后使x变成了y,这时如果操作次数是奇数,那么就无法达成,是偶数,我们可以通过反复加减的方式来使得x==y。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        ll x,y,m;
        scanf("%d%d%d",&x,&y,&m);
        ll s=abs(x-y);
        if(m>=s&&(s&1)==(m&1)) printf("Yes\n");
        else printf("No\n");
    }
}

填数
100分以下做法:我也不知道怎么写
100分做法:
首先,对于没有限制的,显然我们填1即可,对于限制1,贪心的使得a[i]==a[i-1],对于限制2,贪心的使得a[i]==a[i-1]+1,这样贪心下去,然后判断最终得到的总和是否小于等于m即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
int b[N];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%d",&b[i]);
        bool flag=true;
        int pre=0,sum=0;
        for(int i=1;i<=n;i++)
        {
            if(b[i]==0) sum++,pre=1;
            else if(b[i]==1) sum+=pre;
            else sum+=pre+1,pre++;
            if(sum>m) {flag=false;break;}
        }
        printf(flag?"Yes\n":"No\n");
    }
}

区间中最多的数
10分做法:暴力枚举
100分做法:1<=a[i]<=100,用前缀和维护1100每个数出现的次数,就可以O(1)的查询某个数在区间里出现的次数了,然后对于一次查询,只需要O(100)的暴力去统计即可,时间复杂度O(100q+100n)
50分做法:在100分做法的基础上,用数据结构去维护1
100每个数出现的次数,咋们就可以TLE了,时间复杂度O(100qlog2(n)+100nlog2(n))。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,q,a[N],sum[N][105];
int main()
{
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=100;j++)
        sum[i][j]=sum[i-1][j]+(a[i]==j);
    while(q--)
    {
        int l,r,mx=0,ans;
        scanf("%d%d",&l,&r);
        for(int i=1;i<=100;i++)
            if(sum[r][i]-sum[l-1][i]>=mx) ans=i,mx=sum[r][i]-sum[l-1][i];
        printf("%d\n",ans);
    }
}

子段和
100分以下做法:我也不知道怎么写
100分做法:
1.f[i][j]表示[i,j]这段区间的和,开一个vis数组保存每个和出现的次数,如果之星操作1,我们只需要删除n个区间的值,执行操作2,只需要假如n个区间的值,时间复杂度O(nm)。
2.记录前缀和和一个vis数组,vis数组里保存某个前缀和出现的次数,对于每次查询O(n)的去跑所有前缀和,判断sum-x这个前缀和是否存在即可,时间复杂度最坏O(nm)。
3.由于数据水,时间复杂度O(n^2 m)的算法也被放过了,很遗憾我的数据这么水。
做法1:

#include<bits/stdc++.h>
using namespace std;
const int N=255;
int n,m,a[N],sum[N],vis[N*100000];
int main()
{
    scanf("%d%d",&n,&m);
    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],vis[sum[i]]++;
    vis[0]=1;
    while(m--)
    {
        int opt,x;
        scanf("%d",&opt);
        if(opt!=1) scanf("%d",&x);
        if(opt==1)
            vis[sum[n]]--,n--;
        else if(opt==2) a[++n]=x,sum[n]=sum[n-1]+a[n],vis[sum[n]]++;
        else
        {
            bool flag=false;
            for(int i=n;i>=1;i--)
                if(sum[i]>=x&&vis[sum[i]-x])
                    flag=true;
            printf(flag?"Yes\n":"No\n");
        }
    }
}

做法2:

#include<bits/stdc++.h>
using namespace std;
const int N=255;
int n,m,a[N],f[N][N],vis[N*100000];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)
        for(int j=i;j<=n;j++)
    {
        if(i==j) f[i][j]=a[i];
        else f[i][j]=f[i][j-1]+a[j];
        vis[f[i][j]]++;
    }
    while(m--)
    {
        int opt,x;
        scanf("%d",&opt);
        if(opt!=1) scanf("%d",&x);
        if(opt==1)
        {
            for(int i=1;i<=n;i++)
                vis[f[i][n]]--;
            n--;
        }
        else if(opt==2)
        {
            a[++n]=x;
            for(int i=1;i<=n;i++)
            {
                if(i==n) f[i][n]=a[n];
                else f[i][n]=f[i][n-1]+a[n];
                vis[f[i][n]]++;
            }
        }
        else
            printf(vis[x]?"Yes\n":"No\n");
    }
}

做法3:

#include<bits/stdc++.h>
using namespace std;
const int N=255;
int n,m,a[N];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    while(m--)
    {
        int opt,x;
        scanf("%d",&opt);
        if(opt!=1) scanf("%d",&x);
        if(opt==1)
            n--;
        else if(opt==2) a[++n]=x;
        else
        {
            bool flag=false;
            for(int i=1;i<=n;i++)
            {
                int t=0;
                for(int j=i;j<=n;j++)
                {
                    t+=a[j];
                    if(t==x) flag=true;
                }
            }
            printf(flag?"Yes\n":"No\n");
        }
    }
}
全部评论

相关推荐

自从我室友在计算机导论课上听说了“刷&nbsp;LeetCode&nbsp;是进入大厂的敲门砖”,整个人就跟走火入魔了一样。他在宿舍门口贴了一张A4纸,上面写着:“正在&nbsp;DP,请勿打扰,否则&nbsp;Time&nbsp;Limit&nbsp;Exceeded。”日记本的扉页被他用黑色水笔加粗描了三遍:“Talk&nbsp;is&nbsp;cheap.&nbsp;Show&nbsp;me&nbsp;the&nbsp;code。”连宿舍聚餐,他都要给我们讲解:“今天的座位安排可以用回溯算法解决,但为了避免栈溢出,我建议用动态规划。来,这是状态转移方程:dp[i][j]&nbsp;代表第&nbsp;i&nbsp;个人坐在第&nbsp;j&nbsp;个位置的最优解。”我让他去楼下取个快递,他不直接去,非要在门口踱步,嘴里念念有词:“这是一个图的遍历问题。从宿舍楼(root)到驿站(target&nbsp;node),我应该用&nbsp;BFS&nbsp;还是&nbsp;DFS?嗯,求最短路径,还是广度优先好。”和同学约好出去开黑,他会提前发消息:“集合点&nbsp;(x,&nbsp;y),我们俩的路径有&nbsp;k&nbsp;个交点,为了最小化时间复杂度,应该在&nbsp;(x/2,&nbsp;y/2)&nbsp;处汇合。”有一次另一个室友低血糖犯了,让他帮忙找颗糖,他居然冷静地分析道:“别急,这是一个查找问题。零食箱是无序数组,暴力查找是&nbsp;O(n)。如果按甜度排序,我就可以用二分查找,时间复杂度降到&nbsp;O(log&nbsp;n)。”他做卫生也要讲究算法效率:“拖地是典型的岛屿问题,要先把连通的污渍区块都清理掉。倒垃圾可以用双指针法,一个指针从左往右,一个从右往左,能最快匹配垃圾分类。”现在我们宿舍的画风已经完全变了,大家不聊游戏和妹子,对话都是这样的:“你&nbsp;Two&nbsp;Sum&nbsp;刷了几遍了?”“别提了,昨天遇到一道&nbsp;Hard&nbsp;题,我连暴力解都想不出来,最后只能看题解。你呢?”“我动态规划还不行,总是找不到最优子结构。今天那道接雨水给我整麻了。”……LeetCode&nbsp;真的害了我室友!!!
老六f:编程嘉豪来了
AI时代还有必要刷lee...
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务