第二周111

1.路径计数


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

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

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

输入格式

第一行一个正整数n�。

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

输出格式

一个整数,表示答案。

样例输入
3
1 1 1
1 0 1
1 1 1
样例输出
2

思路

dp模拟

代码

#include <bits/stdc++.h>
using namespace std;
#define rep(i, l, r) for (int i = l; i <= r; ++i)
#define repd(i, l, r) for (int i = l; i >= r; --i)

const int mod=1e9+7;
const int N=1e3+10;
int f[N][N],a[N][N];

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    int n;
    cin>>n;
    rep(i,1,n){
        rep(j,1,n) cin>>a[i][j];
    }
    f[1][1]=1;
    rep(i,1,n){
        rep(j,1,n){
            if(i==1 && j==1) continue;
            if(a[i][j]==1) f[i][j]=(f[i-1][j]+f[i][j-1])%mod;
        }
    }
    cout<<f[n][n]<<endl;
    return 0;
}

2.最大和上升子序列


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

输入格式

第一行一个数字 n�。

接下来一行 n� 个整数 a1,a2,…,an�1,�2,…,��。

输出格式

一个数,表示答案。

样例输入
6
3 7 4 2 6 8
样例输出
21

思路

和最大上升子序列一个思路,只不过寻找的是和最大

代码

#include <bits/stdc++.h>
using namespace std;
#define rep(i, l, r) for (int i = l; i <= r; i++)
#define rep1(i, l, r) for (int i = l; i < r; i++)
const int N =1010;
int a[N], f[N],  n,T;

int main(){
        cin>>n;
        int res = 0;
        rep(i,1,n) cin>>a[i];
        rep(i,1,n){
            f[i] = a[i];
            rep1(j,1,i){
                if(a[j] < a[i]) f[i] = max(f[i],f[j]+a[i]);
            }
            res = max(res,f[i]);
        }
        cout<<res<<endl;

    return 0;
}

3.加一


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

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

输入格式

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

接下来 t� 行,每行有两个整数 n� 和 m�,表示最初的数字和进行多少次操作。

输出格式

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

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

思路

动态规划,设置f数组。

代码

#include<bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(int i = l;i<=r;i++)
const int MOD = 1e9 + 7;
const int N = 200010;
long long f[N+50][10];
int n;

int main(){
    scanf("%d", &n);
    rep(i,0,9) f[0][i] = 1;
    rep(i,1,N){
        rep(j,1,9)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;
        }
        printf("%d\n",res);
    }
    return 0;
}

4.跳跳


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

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

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

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

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

输入格式

第一行一个整数 N�。

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

输出格式

一个数,表示答案。

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

思路

二分查找

代码

#include<bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(int i = l;i<r;i++)
typedef long long ll;
typedef pair<ll, ll> PII;
const int MOD = 1e9 + 7;
const int N = 200010;
long long f[N+50][10];

int gcd(int x, int y){
    while (y ^= x ^= y ^= x %= y);
    return x;
}

int main(){
    long long n, x, y;
    vector<PII>v;
    cin>>n;
    map<PII, int>mymap;

    rep(i,0,n){
        cin>>x>>y;
        v.push_back({ x,y });
    }
    long long res = 0;
    rep(i,0,n){
        rep(j,0,n){
            if(j == i) continue;
            int x = v[j].first - v[i].first, y = v[j].second - v[i].second;
            if (x == 0 || y == 0){
                x = x != 0 ? x/abs(x) : x;
                y = y != 0 ? y/abs(y) : y;
            }
            else{
                int num = abs(gcd(x, y));
                x /= num;
                y /= num;
            }
            if (mymap[{x, y}] == 0){
                mymap[{x, y}] = 1;
                res++;
            }
        }
    }
    cout<<res<<endl;
    return 0;
}

5.异或和或


对于一个长度为 n� 的0101序列 a1,a2,…,an�1,�2,…,��。

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

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

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

  • 然后令 ai=x,aj=y��=�,��=� 或 ai=y,aj=x��=�,��=�。

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

输入格式

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

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

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

输出格式

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

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

思路

依次判断数据,简单模拟

代码

#include <bits/stdc++.h>
using namespace std;

string s,s2;

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    int t;
    cin>>t;
    while(t--){
        cin>>s>>s2;
        int one=0,zero=0;
        if(s.size()!=s2.size()){
            cout<<"NO"<<endl;
            continue;
        }
        for(int i=0;i<s.size();i++){
            if(s[i]=='0')zero++;
            else one++;
        }
        int one2=0,zero2=0;
        for(int i=0;i<s2.size();i++){
            if(s2[i]=='0')zero2++;
            else one2++;
        }
        if(one&&!one2) cout<<"NO"<<endl;
        else if(!one&&one2) cout<<"NO"<<endl;
        else if(one2&&one) cout<<"YES"<<endl;
        else cout<<"YES"<<endl;
    }
    return 0;
}

6.删删


给定一个字符串,你可以删除多个(可以是 00) 相同 的字符,这样操作之后,你能否得到一个回文串?如果能,求最小化删除的个数。

输入格式

多组数据。

每一组数据包含两行,分别为字符串的长度 N�,以及一个仅由小写字母组成的字符串 S�。

输出格式

对于每一组数据,输出一行。

如果不可能得到一个回文串,输出 −1−1。反之则输出最小操作次数。

样例输入
4
8
bilibili
3
qwq
9
daimayuan
7
xcpcxpc
样例输出
1
0
-1
2

思路

枚举,以此判断。

代码

#include<bits/stdc++.h>
using namespace std;
int main() {
    int t;
    cin >> t;
    while (t--){
        char c = '#';
        int n,res=1e9;
        bool flag = true;
        string str;
        cin >> n >> str;
        for (char i = 'a'; i <= 'z'; i++){
            bool flag = true;
            int l = 0, r = n - 1,ans=0;
            while(l < r){
                if (str[l] == str[r])l++, r--;
                else{
                    if (str[l] == i)l++, ans++;
                    else if (str[r] == i)r--, ans++;
                    else{
                        flag = false;
                        break;
                    }
                }
            }
            if (flag)res = min(res, ans);
        }
        if (res==1e9)cout << -1 <<endl
        else cout<<res<<endl;
    }
    return 0;
}

7.出栈序列判断


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

比如 n=3�=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�。接下来一行 n� 个整数,表示出栈序列。

输出格式

输出 2n2� 行,每行一个 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

思路

将数字按排序依次插入栈,插入的同时与数组第一位数比较。若相等,则出栈。继续插入和数组第二位数比较...直到栈空,得到答案。

代码

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(auto i = a; i <= b; i++)

int n,a[100005];
stack<int> s;

int main(){
    cin>>n;
    rep(i,1,n) cin>>a[i];
    int cnt = 1;
    rep(i,1,n){
        s.push(i);
        printf("push %d\n",i);
        while(!s.empty() && s.top() == a[cnt]){
            s.pop();
            cnt++;
            puts("pop");
        }
    }
}

8.序列维护


你有一个序列,现在你要支持几种操作:

  • insert x y,在从前往后的第x�个元素后面插入y�这个数。如果x=0�=0,那么就在开头插入。

  • delete x,删除从前往后的第x�个元素。

  • query k,询问从前往后数第k�个元素是多少。

输入格式

第一行一个整数m�,表示操作个数。

接下来m�行,每行一个上面所述的操作。

输出格式

输出若干行,对于每个查询操作,输出答案。

样例输入
10
insert 0 1
insert 1 2
query 1
query 2
insert 0 3
query 1
delete 1
query 1
insert 1 4 
query 2
样例输出
1
2
3
1
4

思路

vector的插入操作,删除操作,查询操作。

代码

#include <bits/stdc++.h>
using namespace std;
const int N=1e3+10;
int a[N];
vector<int>v;
int main() {
    int n;
    cin>>n;
    string s;
    int start,val;
    while(n--){
        cin>>s;
        if(s == "insert"){
            cin>>start>>val;
            v.insert(v.begin()+start,val);
        }
        else if(s == "delete"){
            cin>>start;
            v.erase(v.begin()+start-1);
        }
        else if(s== "query"){
            cin>>start;
            cout<<v[start-1]<<endl;
        }
    }
    return 0;
}

9.网格判断


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

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

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

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

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

输入格式

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

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

输出格式

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

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

思路

设置三个数据,依次判断是否成立。

代码

#include<bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(int i = l;i<=r;i++)

int main(){
    int n;
    cin>>n;
    vector<int> s(n + 1);
    vector<vector<char>> v(n + 1, vector<char>(n + 1));
    string str;
    rep(i,1,n){
        cin>>str;
        rep(j,1,n){
            v[i][j] = str[j - 1];
            s[j] = s[j - 1];
            if (str[j - 1] == 'W') s[j] += 1;
            if (j >= 4 && (s[j]==s[j-3] || s[j]-s[j-3]==3)){
                cout << 0 << endl;
                return 0;
            }
        }
        if (s[n] != n / 2){
            cout << 0 << endl;
            return 0;
        }
    }
   rep(i,1,n){
         rep(j,1,n){
            s[j] = s[j - 1];
            if (v[j][i] == 'W')s[j] += 1;
            if (j >= 4 && (s[j] == s[j - 3] || s[j] - s[j - 3] == 3)){
                cout<<0<<endl;
                return 0;
            }
        }
        if (s[n] != n / 2){
            cout<<0<<endl;
            return 0;
        }
    }
    cout<<1<<endl;
    return 0;
}

10.整齐的数组


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

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

输入格式

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

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

输出格式

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

样例输入

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

思路

代码

#include<bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(int i = l;i<=r;i++)
const int MOD = 1e9 + 7;
const int N = 1e5 + 10;
long long a[N], b[N], w[N], v[N], f[N];
int t;
int main() {
    cin>>t;
    while (t--){
        int n, res = 0, min_num = 1e9,k=-1;
        cin>>n;
        vector<int>v(n + 1);
        rep(i,1,n){
            cin >> v[i];
            min_num = min(min_num, v[i]);
        }
        map<int, int> mymap;
        rep(i,1,n){
            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 res++;
        }
        for(auto i : mymap)
            if (i.second >= n - res)k = max(k, i.first);
        cout<<k<<endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值