#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. 跳跳
平面上给定了一些整点(横纵坐标均为整数的点),被称为 “魔法阵”。魔法少女派派想要在各魔法阵之间传送,每一次传送,她将使用下面的方式:
刚开始,派派已经位于某传送阵之上;
如果派派掌握一种魔法 (A,B)(A,B),其中 A,BA,B 均为整数。使用一次这个魔法可以让派派从任意整点 (X,Y)(X,Y) 瞬间移动至 (X+A,Y+B)(X+A,Y+B);
选择一种魔法并开始传送,在一次传送过程中可以使用多次该魔法,但在抵达下一个传送阵之前仅能使用这一种魔法。
问派派至少需要掌握多少种魔法,才能在从任意魔法阵直接传送到任意魔法阵?
输入格式
第一行一个整数 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序列
我们称一个字符串为好字符串,指这个字符串中只包含0和1。
现在有一个好字符串,求这个字符串中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还能这样用,长知识了
#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。我们可以通过 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,输入一定是个合法的出栈序列。
用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