#126. 路径计数、#289. 最大和上升子序列、#498. 加一、#496. 跳跳、#500. 异或和或、#502. 01序列、出栈序列判断

#126. 路径计数


有一个n×nn×n的网格,有些格子是可以通行的,有些格子是障碍。

一开始你在左上角的位置,你可以每一步往下或者往右走,问有多少种走到右下角的方案。

由于答案很大,输出对109+7109+7取模的结果。

输入格式

第一行一个正整数nn

接下来nn行,每行nn个正整数,11表示可以通行,00表示不能通行。

输出格式

一个整数,表示答案。

样例输入
3
1 1 1
1 0 1
1 1 1
样例输出
2
数据规模

对于100%100%的数据,保证2≤n≤1002≤n≤100,左上角右下角都是可以通行的。

没看数据直接搜索,于是光荣的0分了QAQ,用动态规划即可,开始赋初值,除了第一行和第一列外的每一个都只能由上面和右边的格子过来,记得开longlong和及时取余!!
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
int n,ans;
const int N = 105;
int mod = 1e9+7;
int mp[N][N];
ll f[N][N];
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)cin>>mp[i][j];
         f[1][1]=1;
    for(int i=2;i<=n;i++)//赋初值 
    {
        if(mp[1][i])f[1][i]+=f[1][i-1];
        if(mp[i][1])f[i][1]+=f[i-1][1];
    }
    for(int i=2;i<=n;i++)
    for(int j=2;j<=n;j++)//相当于记忆化搜索 
    {
        if(mp[i][j])f[i][j]=(f[i-1][j]%mod+f[i][j-1]%mod)%mod;
        else //可不写
        f[i][j]=0;
    }
     cout<<f[n][n];    
    return 0;
}

#289. 最大和上升子序列


给定一个长度为 nn 的数组 a1,a2,…,ana1,a2,…,an,问其中的和最大的上升子序列。也就是说,我们要找到数组 p1,p2,…,pmp1,p2,…,pm,满足 1≤p1<p2<⋯<pm≤n1≤p1<p2<⋯<pm≤n 并且 ap1<ap2<⋯<apmap1<ap2<⋯<apm,使得ap1+ap2+⋯+apmap1+ap2+⋯+apm最大。

输入格式

第一行一个数字 nn

接下来一行 nn 个整数 a1,a2,…,ana1,a2,…,an

输出格式

一个数,表示答案。

样例输入
6
3 7 4 2 6 8
样例输出
21
f[i]表示a1-ai的之间最大上升子序列的和,所以需要用ans存储最大值,转移方程式为:f[i]=max(f[i],f[k]+a[j]),其中j<i,a[j]<=a[i],
#include<iostream>
using namespace std;
const int N = 1e3+10;
int f[N],a[N],ans;
int main()
{
    int n;cin>>n;
    for(int i=1;i<=n;i++)
    {
    cin>>a[i];
    }
    f[1]=a[1];
    ans=a[1];
    for(int i=2;i<=n;i++)
    {
        f[i]=a[i];
        for(int j=1;j<i;j++)
        {
            if(a[i]>=a[j])
            {
                f[i]=max(f[i],f[j]+a[i]);
            }
        }
        if(f[i]>ans)ans=f[i];
    }
    cout<<ans;
    return 0;
}

#498. 加一


给定一个整数 nn。你需要对它做 mm 次操作。在一次操作中,你要将这个数的每一位 dd 替换成 d+1d+1。比如,19121912 在进行一次操作后将变成 2102321023

请求出整数 nn 进行了 mm 次操作后的长度。答案可能很大,输出对 109+7109+7 取模后的结果。

输入格式

第一行一个整数 tt,表示测试单元的个数。

接下来 tt 行,每行有两个整数 nn 和 mm,表示最初的数字和进行多少次操作。

输出格式

对于每个测试单元输出最终数字的长度,答案对 109+7109+7 取模。

样例输入
5
1912 1
5 6
999 1
88 2
12 100
样例输出
5
2
6
4
2115
数据规模

所有数据保证 1≤t≤2⋅1051≤t≤2⋅105,1≤n≤1091≤n≤109,1≤m≤2⋅1051≤m≤2⋅105

(214条消息) 2022-03-08每日刷题打卡_给定一个正整数 n。你可以对 n 的任意一位数字执行任意次以下 2 种操作: 1. 将该_你好_Ä的博客-CSDN博客

#include<bits/stdc++.h>
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<map>
#include<unordered_map>
#include<stack>

typedef long long ll;
typedef pair<int, int>PII; 
const int MOD = 1e9 + 7;
const int N = 200010;
ll f[N+50][10];

int main()
{
    int n;
    scanf("%d", &n);
    for (int i = 0; i <= 9; i++)f[0][i] = 1;
    for (int i = 1; i <= N; i++)
    {
        for (int j = 1; j <= 9; j++)f[i][j - 1] = f[i-1][j];
        f[i][9] = (f[i-1][1] + f[i-1][0]) % MOD;
    }
    while (n--)
    {
        char str[20];
        int m, res = 0;
        scanf("%s %d", &str, &m);
        int len = strlen(str);
        for (int i = 0; i < len; i++)
        {
            res += f[m][str[i] - '0'];
            res %= MOD;
        }
        cout << res << "\n";
    }
    return 0;
}
下面自己写的超时,人麻了,改两小时不改了,拜拜了您。
题目只要求长度,那么我们计算各个数字的个数即可,遇到9时,0和1的个数均加1,长度加1.
#include <iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
const int mod = 1e9 + 7;
ll a[2][10];
int t,m,n=1;
char sh[20];
int  main() {
    scanf("%d", &t);
    while (t--)
    {
        memset(a, 0, sizeof(a));
        scanf("%s %d", sh, &m);
        int len = strlen(sh),l=0;
        n = 1;
        for (int i = 0; i < len; i++)a[n][sh[i] - '0']++;//计算各个数字个数
        for (int k = 1; k <= m; k++) {
            for (int i = 0; i <= 9; i++)
            {
                if (i == 9) 
                {
                    a[n ^ 1][0] = (a[n^1][0] + a[n][i]) % mod ;
                    a[n ^ 1][1] = (a[n^1][1] + a[n][i]) % mod;
                    len = (len + a[n][9] % mod) % mod;
                }
                
                else
                    a[n ^ 1][i + 1] = a[n][i]%mod;
            }  
            for (int i = 0; i <= 9; i++)a[n][i] = 0;//清空
            n ^= 1;
        }
        printf("%d\n",len);
    }
    return 0;
}

#496. 跳跳


平面上给定了一些整点(横纵坐标均为整数的点),被称为 “魔法阵”。魔法少女派派想要在各魔法阵之间传送,每一次传送,她将使用下面的方式:

  1. 刚开始,派派已经位于某传送阵之上;

  1. 如果派派掌握一种魔法 (A,B)(A,B),其中 A,BA,B 均为整数。使用一次这个魔法可以让派派从任意整点 (X,Y)(X,Y) 瞬间移动至 (X+A,Y+B)(X+A,Y+B)

  1. 选择一种魔法并开始传送,在一次传送过程中可以使用多次该魔法,但在抵达下一个传送阵之前仅能使用这一种魔法

问派派至少需要掌握多少种魔法,才能在从任意魔法阵直接传送到任意魔法阵?

输入格式

第一行一个整数 NN

接下来一行 NN 行,每行包含两个整数 Xi,YiXi,Yi, 表示每个魔法阵的坐标。

输出格式

一个数,表示答案。

样例1输入
3
1 1
4 5
1 4
样例1输出
6

解释: 任务是从 (1,1)(1,1) 传送至 (4,5)(4,5) 以及 (1,4)(1,4) 、从 (4,5)(4,5) 传送至 (1,1)(1,1) 以及 (1,4)(1,4) 、从 (1,4)(1,4) 传送至 (1,1)(1,1) 以及 (4,5)(4,5)

注意你不能使用 (0,3)+(3,1)(0,3)+(3,1) 的魔法从 (1,1)(1,1) 到达 (4,5)(4,5)。因为每次移动,你只能使用一种魔法。

当然,你可以学习 (0,1)(0,1),那样的话,从 (1,1)(1,1) 到达 (1,4)(1,4) 则需要使用 33 次 (0,1)(0,1) 魔法了。

样例2输入
3
1 1
2 2
1000000000 1000000000
样例2输出
2
数据规模
  • N∈[10,500]N∈[10,500]

  • Xi,Yi∈[0,109]Xi,Yi∈[0,109], 但保证坐标之间两两不同

从(x1,y1)到(x2,y2)需要移动(x2-x1,y2-y1),因为题目不限制移动次数,所以每次取最简形式,即(x2-x1,y2-y1)同除最大公约数,以保证掌握的魔法种数最小。注意正负。
#include<iostream>
#include<map>
#include<utility>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
typedef pair<int, int>pi;
vector <pi> v;
map <pi, int>mp;
long long ans;
int n;
int gcd(int a, int b)
{
    return b ? gcd(b, a % b) : a;
}
int main()
{
    cin >> n;
    int x, y;
    for (int i = 1; i <= n; i++) {
        cin >> x >> y;
        v.push_back({ x,y });
    }
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
        {
            if (i == j)continue;
            x = v[i].first - v[j].first;
            y = v[i].second - v[j].second;
            if (x == 0)y = y == 0 ? y : y / (abs(y));
            else if (y == 0)x = x == 0 ? x : x / abs(x);
            else
            {
                int g = abs(gcd(x, y));
                x /= g, y /= g;
            }
            if (mp[{x, y}] == 0)//查找该魔法种类是否已经掌握
            {
                ans++;
                mp[{x, y}] = 1;
            }
        }
    }
    cout << ans << '\n';
    return 0;
}

#500. 异或和或


对于一个长度为 nn 的0101序列 a1,a2,…,ana1,a2,…,an

你可以执行以下操作任意多次:

  • 选择两个下标 1≤i,j≤n(i≠j)1≤i,j≤n(i≠j)

  • 记x=ai xor ajx=ai xor aj , y=ai or ajy=ai or aj , 其中 xorxor 表示按位异或 , oror 表示按位或。

  • 然后令 ai=x,aj=yai=x,aj=y 或 ai=y,aj=xai=y,aj=x

给定两个0101序列 s,ts,t , 请你判断是否可以通过有限次(可以为00次)操作将序列 ss 变为 tt

输入格式

第一行一个整数 tt , 表示数据的组数(1≤t≤103)(1≤t≤103)。接下来 tt 组数据:

每组第一行一个0101字符串 s(1≤|s|≤103)s(1≤|s|≤103),每组第二行一个0101字符串 t(1≤|t|≤103)t(1≤|t|≤103)

注意:|s||s| 可能不等于 |t||t|

输出格式

如果可以通过有限次(可以为00次)操作将序列 ss 变为 tt , 输出 YES , 否则输出 NO

样例输入
2
001
011
11
101
样例输出
YES
NO
样例解释

第一组数据选择 i=2,j=3i=2,j=3 , 那么 x=1,y=1x=1,y=1 , 接着令 ai=x,aj=yai=x,aj=y 即可得到 tt 序列。

第二组数据 |s|=2,|t|=3|s|=2,|t|=3 显然无法满足要求。

分析发现,只要序列中有1,其都能全部变为1,所以我们只用看输入的序列是否含有1即可。长度把不同也不能相互转换。
注意在循环里面使用数组一定要记得置零!!!!!!!!
#include<iostream>
#include<cstring>
using namespace std;
string s1,s2;
int t,a[2],b[2];
int main()
{
     ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin>>t;
    while(t--)
    {
    memset(a,0,sizeof a);
    memset(b,0,sizeof b);
    cin>>s1>>s2;
    if(s1.size()!=s2.size()){
    cout<<"NO"<<endl;
    continue;
    }
    for(int i=0;i<s1.size();i++){
    a[s1[i]-'0']++;
    }
    for(int i=0;i<s2.size();i++)
    {
    b[s2[i]-'0']++;
    }
    if(a[1]&&b[1]||!a[1]&&!b[1])cout<<"YES"<<endl;
    else cout<<"NO"<<endl;
    }
 } 

#502. 01序列


我们称一个字符串为好字符串,指这个字符串中只包含01

现在有一个好字符串,求这个字符串中1恰好出现kk次的子串有多少个。

输入格式

第一行给出一个数字kk,表示子串中1的个数。

第二行给出好字符串。

输出格式

输出一个整数,表示好字符串中有多少个符合条件的子串

数据范围

0≤k≤106, |s|≤1060≤k≤106, |s|≤106

样例输入1
1
1010
样例输出1
6
样例输入2
2
01010
样例输出2
4
运用前缀和加哈希表求解,直接暴力枚举两轮会超时,f[i]表示前i个字符中含有1的个数。
#include<iostream>
#include<cstring>
#include<unordered_map>
#include<cstdio>
#include<cstdio>
#define endl '\n'
using namespace std;
const int N = 1e6+10;
typedef long long ll;
int f[N],k;//前n个字符里面有f[n]个1 
string sh;
unordered_map <int,ll> mp;
ll ans,res;
int main()
{
    cin>>k>>sh;
    mp[0]++;//初始化为1,相乘的时候用
    if(k){
    for(int i=0;i<sh.size();i++)
    {
        if(sh[i]=='1')f[i+1]=f[i]+1;
        else f[i+1]=f[i];
        mp[f[i+1]]++;//含有1的个数为f[i+1]的子串的个数加1
    }
        while(mp[ans+k]!=0)//一直枚举含1的个数为ans+k的子串数目,如果mp[ans+k]==0说明子串最多含有ans+k-1个1,不用向后枚举了 
    {
        res+=mp[ans]*mp[ans+k];// 每一个前缀和为ans+k的位置,都能和所有前缀和为ans的位置形成好子串
        ans++;//枚举下一个位置 
    } 
}
     else //子串中1的个数为0的情况 
     {
         sh+='1';//防止字符串全为0
         for(int i=0;i<sh.size();i++)
         {
             if(sh[i]=='0')ans++;//看有几个连续的0,找出该连续字符串子串个数 
             else 
             {
                 res+=ans*(ans+1)/2;
                 ans=0;//置0 
             }
        }
     }
     cout<<res;
    return 0;
}

出栈序列判断

现在有一个栈,有 nn 个元素,分别为 1,2,…,n1,2,…,n。我们可以通过 push 和 pop 操作,将这 nn 个元素依次放入栈中,然后从栈中弹出,依次把出栈的元素写下来得到的序列就是出栈序列。

比如 n=3n=3,如果执行 push 1, push 2, pop, push 3, pop, pop,那么我们 pop 操作得到的元素依次是 2,3,12,3,1。也就是说出栈序列就是 2,3,12,3,1。

现在给定一个合法的出栈序列,请输出一个合法的由 push 和 pop 操作构成的操作序列。这里要求 push 操作一定是按 1,2,…,n1,2,…,n 的顺序。

输入格式

第一行一个整数 nn。接下来一行 nn 个整数,表示出栈序列。

输出格式

输出 2n2n 行,每行一个 push 或 pop 操作,可以证明一个出栈序列对应的操作序列是唯一的。

样例输入1
3
2 3 1
样例输出1
push 1
push 2
pop
push 3
pop
pop
样例输入2
5
1 3 5 4 2
样例输出2
push 1
pop
push 2
push 3
pop
push 4
push 5
pop
pop
pop
数据规模

对于 100%100% 的数据,保证 1≤n≤1000001≤n≤100000,输入一定是个合法的出栈序列。

vector还能这样用,长知识了

vector用法

#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
using namespace std;
vector<int> v;
int m;
string s;
int main()
{
    scanf("%d",&m);
    while(m--)
    {
        cin>>s;
        if(s=="insert")
        {
            int pos,num;
            scanf("%d%d",&pos,&num);
            v.insert(v.begin()+pos,num);
        }
        else if(s=="query")
        {
            int pos;
            scanf("%d",&pos);
            printf("%d\n",v[pos-1]);
        }
        else 
        {
            int pos;
            scanf("%d",&pos);
            v.erase(v.begin()+pos-1);
        }
    }
    return 0;
}

出栈序列判断


现在有一个栈,有 nn 个元素,分别为 1,2,…,n1,2,…,n。我们可以通过 pushpop 操作,将这 nn 个元素依次放入栈中,然后从栈中弹出,依次把出栈的元素写下来得到的序列就是出栈序列。

比如 n=3n=3,如果执行 push 1, push 2, pop, push 3, pop, pop,那么我们 pop 操作得到的元素依次是 2,3,12,3,1。也就是说出栈序列就是 2,3,12,3,1

现在给定一个合法的出栈序列,请输出一个合法的由 pushpop 操作构成的操作序列。这里要求 push 操作一定是按 1,2,…,n1,2,…,n 的顺序。

输入格式

第一行一个整数 nn。接下来一行 nn 个整数,表示出栈序列。

输出格式

输出 2n2n 行,每行一个 pushpop 操作,可以证明一个出栈序列对应的操作序列是唯一的。

样例输入1
3
2 3 1
样例输出1
push 1
push 2
pop
push 3
pop
pop
样例输入2
5
1 3 5 4 2
样例输出2
push 1
pop
push 2
push 3
pop
push 4
push 5
pop
pop
pop
数据规模

对于 100%100% 的数据,保证 1≤n≤1000001≤n≤100000,输入一定是个合法的出栈序列。

用stl里的栈进行操作,注意输入输出语句会有很多条,可以用scanf和printf来进行输入输出防止超时。
(用数组模拟栈的话会超时)
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<stack>
using namespace std;
const int N = 1e5+10;
stack<int > s;
int a[N],n,num=1;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)
    {
        s.push(i);
        printf("push %d\n",i);
        while(!s.empty()&&s.top()==a[num])
        {
            s.pop();
            num++;
            printf("pop\n");
        }
    }
    while(!s.empty())
    {
        s.pop();
        printf("pop\n");
    }
    return 0; 
}

超时做法,惊醒自己不算时间复杂度...每次读入一个数就去遍历它前面比它小的数,若比它小的数没有进栈,便需要先读入。当需要出栈的数为最大的数时,说明前面比它小的数已经全部读入了,这时候就只需要进行出栈操作了,cnt用来记录栈里面还剩余的数

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<stack>
using namespace std;
const int N = 1e5+10;
int vis[N],n,cnt,a[N];
//超时了 
int main()
{

    scanf("%d",&n);cnt = n;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        for(int j=1;j<=a[i];j++)
        {
            if(!vis[j])
            {
                vis[j]=1;
                printf("push %d\n",j);
            }
        }
        printf("pop\n");
        cnt--;
        if(a[i]==n)break;
    }
    while(cnt--)printf("pop\n");
    return 0;
}
代码源崩了,就先借用大佬的题解

整齐的数组


Polycarp 有一个长度为 nn 的数组 a1,a2,...,ana1,a2,...,an(nn 是偶数)。Polycarp 还得到了一个正整数 kk,他开始对数组 aa 做如下操作:选择一个下标 i (1≤i≤n)i (1≤i≤n) 使 aiai 减去 kk。

在 Polycarp 进行若干次操作后(可能 00 次),数组 aa 中的所有数都变成相同的了。请你找到最大的符合要求的 kk,如果 kk 可以为任意大,请输出 −1−1。

输入格式

第一行一个整数 tt,表示测试单元的个数。

接下来每个测试单元有两行。第一行包含一个偶数 nn。第二行包含 n 个整数 a1,a2,...,ana1,a2,...,an。

输出格式

对于每个测试单元输出单独一行一个整数 k (k≥1)k (k≥1) —— Polycarp 能用来对数组进行操作的最大的数,或者 −1−1 —— 如果 kk 能任意大的话。

样例输入

3
6
1 5 3 1 1 5
8
-1 0 1 -1 0 1 -1 0
4
100 -1000 -1000 -1000

样例输出

2
1
1100

数据规模

所有数据保证 1≤t≤101≤t≤10,4≤n≤404≤n≤40(nn 是偶数),−106≤ai≤106−106≤ai≤106,并且 n 的总和不超过100。

2022-03-15每日刷题打卡 - 掘金 (juejin.cn)

题解见上

#include<iostream>
#include<vector>
#include<cstring>
#include<map>
#include<unordered_map>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
ll a[N], b[N], w[N], v[N], f[N];

int main() {
    int t;
    cin >> t;
    while (t--)
    {
        int n, num = 0, min_num = 1e9,k=-1;
        cin >> n;
        vector<int>v;
        for (int i = 1; i <= n; i++)
        {
            cin >> v[i];
            min_num = min(min_num, v[i]);
        }
        map<int, int>mymap;
        for (int i = 1; i <= n; i++)
        {
            if (v[i] != min_num)
            {
                int ans = v[i] - min_num;
                for (int j = 1; j * j <= ans; j++)
                {
                    if (ans % j == 0)
                    {
                        mymap[j]++;
                        mymap[ans / j]++;
                    }
                }
            }
            else
            {
                num++;
            }
        }
        for (auto i : mymap)
        {
            if (i.second >= n - num)k = max(k, i.first);
        }
        cout << k << '\n';
    }
    return 0;
}
代码源崩了(拖延症QAQ的后果),就先借用大佬的题解

网格判断


您将获得一个 n×nn×n 的网格,网格中每个正方形的颜色为黑色或白色。如果满足以下所有条件,则网格是正确的:

  • 每行的黑色方块数与白色方块数相同。

  • 每列的黑色正方形数与白色方块数相同。

  • 没有行或列具有 33 个及以上相同颜色的连续正方形。

给定网格,确定它是否正确。

输入格式

第一行一个数字 nn(2≤n≤242≤n≤24), 并且数字 nn 是偶数。

接下来 nn 行,每行包含一个长度为nn的由字符B和W组成的字符串,代表网格正方形的颜色。

输出格式

如果网格正确,请打印数字 11 在一行上。否则,请打印数字 00 在一行上。

样例输入
4
WBBW
WBWB
BWWB
BWBW
样例输出
1

代码源:551、网格判断 - 掘金 (juejin.cn)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值