红色题目代表个人认为很难的题目。
第二周
第一题
这题是真的难,以为需要用高精度来暴力模拟,但是事实上是用动态规划来做的,需要用二维数组dp[i][j]代表i操作j次的结果,当i不是9的时候只需要dp[i][j] = dp[i-1][j+1]就可以了。当i是9的时候那么就只能dp[i][j] = dp[1][j-1]+dp[0][j-1]了。最后再把每一位的位数相加就可以了。我看错题了还以为要找的是数值的大小,原来只需要找数值的长度。注意每一位都要取余操作。开long long。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int MAXM = 2E5+30, mod = 1E9+7;
int t;
int m, ans;
char n[20];
int f[MAXM+5][10]; //i经过j次操作后变成f位数
signed main()
{
for(int i = 0; i <= 9; ++i)
{
f[0][i] = 1;
}
for(int i = 1; i <= MAXM; ++i)
{
for(int j = 0; j <= 8; ++j)
{
f[i][j] = f[i-1][j+1];
}
f[i][9] = (f[i-1][0]+f[i-1][1]) % mod;
}
scanf("%d", &t);
while(t--)
{
ans = 0;
scanf("%s %d", n, &m);
int len = strlen(n);
for(int i = 0; i < len; ++i)
{
ans = (ans+f[m][n[i]-'0']) % mod;
}
printf("%d\n", ans);
}
return 0;
}
第二题
这一题就有亿点点的水了。只需要用set来存储每对点x1-x2,y1-y2的数值就好了,注意1->2和2->1是不一样的。记得对x1-x2,y1-y2进行约分,我们可以使用__gcd(x, y)函数求最大公约数,如果害怕gcd函数返回负值就对操作数取绝对值,这样就只能返回正值了。除以最大公约数就行。轻轻松松,简简单单
#include <bits/stdc++.h>
#define int long long
using namespace std;
int a[505], b[505];
int n;
set<pair<int, int> > s; //总共需要多少种魔法
signed main()
{
cin >> n;
for(int i = 1; i <= n; ++i)
{
cin >> a[i] >> b[i];
}
for(int i = 1; i <= n; ++i)
{
for(int j = 1; j <= n; ++j)
{
if(i != j)
{
int g = __gcd(abs(a[i]-a[j]), abs(b[i]-b[j]));//公约数
s.insert(make_pair((a[i]-a[j])/g, (b[i]-b[j])/g));
}
}
}
cout << s.size() << endl;
return 0;
}
第三题
怎么说,这题也是一道考数学的题,题目的意思不难理解,01/10和11可以互相转化,而00却不能被转化。首先,如果两个字符串长度不相等 那肯定是不行的,其次,如果长度相等,如果二者全等也可以。如果长度相等但是不全等,那么有一个为全0就是不能转化,否则就能转化。
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin >> n;
while(n--)
{
string a, b;
cin >> a >> b;
if(a.length() != b.length())
{
cout << "NO" << endl;
}
else if(a == b)
{
cout << "YES" << endl;
}
else
{
int a1=0, b1=0;
for(int i = 0; i < a.length(); ++i)
{
if(a[i] == '1')
{
++a1;
}
if(b[i] == '1')
{
++b1;
}
}
if(a1 == 0 || b1 == 0)
{
cout << "NO" << endl;
}
else
{
cout << "YES" << endl;
}
}
}
return 0;
}
第四题
这个题是一个前缀和的题,首先要定义前缀和数组,然后字符串中找到1就将前缀和+1,定义一个map,让map[sum[i]]++(map用来存放前缀和为n的情况的个数)。注意map[0]初始化为1 .做完这些准备工作后就可以ans+=map[i+k]*map[i],遍历所有可能存在的i直到map[i+k]为0。为什么这样做呢?因为我们要找到起始位置的可能情况和终点的可能情况(左开右闭开区间),但是考虑特殊情况当k=0时要找到所有连续为0的字串然后求每个字串长度n*(n-1)就行了。题目数据量大,开long long,注意初始化条件m[0] = 1不能放在执行步骤(循环)之后,否则会破坏执行结果。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxk = 1E6+6;
int k;
string str;
int sum[maxk];
signed main()
{
cin >> k >> str;
int len = str.length();
str = '0'+str; //这样就能1开始下表了
if(k == 0)
{
int ans = 0, now = 0;
for(int i = 1; i <= len; ++i)
{
if(str[i] == '0')
{
now ++;
}
else
{
ans += now*(now+1)/2;
now = 0;
}
}
ans += now*(now+1)/2; //记得最后一次的运算不要错
cout << ans << endl;
}
else
{
map<int, int> m;
m[0] = 1; //初始化条件
for(int i = 1; i <= len; ++i)
{
sum[i] = sum[i-1]+str[i]-'0';
m[sum[i]]++;
}
int n=0, ans = 0;
while(m[n+k] != 0)
{
ans += m[n+k]*m[n];
n++;
}
cout << ans << endl;
}
return 0;
}
第五题
知道什么是栈吗?嘿嘿,这题需要用到vector来模拟,最开始时一直push,找到第一个出栈的元素然后开始pop,如此循环往复找到下一个出栈的元素pop,如果已经push了所有的元素就一直pop就好了。输入输出量比较大,建议使用快读快写或者scanf和printf,把endl换成'\n'
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n;
cin >> n;
vector<int> arr(n+1);
for(int i = 1; i <= n; ++i)
{
cin >> arr[i];
}
int now = 1;
for(int i = 1; i <= n; ++i)
{
while(now <= arr[i])
{
cout << "push " << now << endl;
now++;
}
cout << "pop" << endl;
}
return 0;
}
第六题
这题就比较容易了,使用c++标准库函数,用vector暴力模拟,注意insert和erase需要用到迭代器。其他就没啥好说。
#include <bits/stdc++.h>
using namespace std;
int main()
{
int m;
vector<int> arr;
cin >> m;
while(m--)
{
string s;
cin >> s;
if(s == "insert")
{
int x, y;
cin >> x >> y;
arr.insert(arr.begin()+x, y);
}
else if(s == "query")
{
int k;
cin >> k;
cout << arr[k-1] << endl;
}
else if(s == "delete")
{
int x;
cin >> x;
arr.erase(arr.begin()+x-1);
}
}
return 0;
}
第七题
我咋也想不到的是我居然连水题都做了好几次才能过,复制粘贴的时候要注意代码的修改,循环程序设计要注意,别让自己想的和写的东西不一样。
#include <bits/stdc++.h>
using namespace std;
int n;
char vec[28][28]; //比较水的题
bool checkh()
{
for(int i = 1; i <= n; ++i)
{
int cnt = 0, lian = 1; //本行的计数和相连的计数。
for(int j = 1; j <= n; ++j)
{
if(vec[i][j] == 'B')
{
cnt++;
}
if(j > 1 && vec[i][j] == vec[i][j-1])
{
lian++;
if(lian >= 3)
{
return 0;
}
}
else
{
lian = 1;
}
}
if(cnt != n/2)
{
return 0;
}
}
return 1;
}
bool checkl()
{
for(int j = 1; j <= n; ++j)
{
int cnt = 0, lian = 1; //本行的计数和相连的计数。
for(int i = 1; i <= n; ++i)
{
if(vec[i][j] == 'B')
{
cnt++;
}
if(i > 1 && vec[i][j] == vec[i-1][j])
{
lian++;
if(lian >= 3)
{
return 0;
}
}
else
{
lian = 1;
}
}
if(cnt != n/2)
{
return 0;
}
}
return 1;
}
int main()
{
cin >> n;
for(int i = 1; i <= n; ++i)
{
for(int j = 1; j <= n; ++j)
{
cin >> vec[i][j];
}
}
if(checkh() && checkl())
{
cout << 1;
}
else
{
cout << 0;
}
return 0;
}
第八题
这题就排一下序然后,再把每个元素和最小的元素求差,求所有差的最大公约数,如果是1就输出-1就可以了。
#include <bits/stdc++.h>
using namespace std;
int t, n;
int main()
{
cin >> t;
while(t--)
{
cin >> n;
vector<int> arr(n+1);
for(int i = 1; i <= n; ++i)
{
cin >> arr[i];
}
sort(arr.begin()+1, arr.end(), less<int>()); //从小到大排序
int now=0, ans = arr[2]-arr[1];
for(int i = 3; i <= n; i++)
{
now = arr[i]-arr[1];
ans = __gcd(now, ans); //找到最大公约数
}
if(ans == 0)
{
cout << -1 << endl;
}
else
{
cout << ans << endl;
}
}
return 0;
}
第九题
自己做的时候没思路,但是其实也没那么难,枚举删除26个字母的所有情况,然后对于这个序列存储为双端队列,进行模拟就可以了。
#include <bits/stdc++.h>
#define inf 0x7f7f7f7f
using namespace std;
int main()
{
int t;
cin >> t;
while(t--)
{
int k;
cin >> k;
deque<char> d; //双端队列
while(k--)
{
char c;
cin >> c;
d.push_back(c);
}
int ans = inf;
for(char c = 'a'; c <= 'z'; ++c)
{
int cnt = 0, now = 0;
deque<char> t = d; //建立缓存
while(!t.empty())
{
if(t.front() == t.back()) //
{
t.pop_front();
if(!t.empty())
{
t.pop_back();
}
}
else if(t.front() == c)
{
t.pop_front();
cnt++;
}
else if(t.back() == c)
{
t.pop_back();
cnt++;
}
else
{
now = 1;
break;
}
}
if(!now) //如果这种情况可行,那么要计数
{
ans = min(ans, cnt);
}
}
if(ans != inf)
cout << ans << endl;
else
cout << -1 << endl;
}
return 0;
}
第十题
前方高能预警!!!
这题主要考察前缀积和动态规划,难度大,看题解我都看的很费劲。sum[i][j]指的是从第i项到第j项的积,记得每乘一项就要取余。然后再利用分治的思想划分数组(类比归并排序),从小到大枚举数组的长度,f[i][j]表示从i到j的子数组中的最大分数。可以利用三重循环枚举中间量,再次切割子数组,求子数组的乘积的分数值就可以了。
#include <bits/stdc++.h>
#include <cstring>
using namespace std;
#define int long long
const int mod=1000003;
const int N=400;
int a[N],sum[N][N];
int f[N][N];
signed main() {
ios_base::sync_with_stdio(0);
cin.tie(0);
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
for(int i=1;i<=n;i++)
{
sum[i][i]=1;
sum[i][i-1]=1;
for(int j=i;j<=n;j++)
{
sum[i][j]=(sum[i][j-1]*a[j])%mod;
}
}
for(int len=2;len<=n;len++)
{
for(int i=1;i+len-1<=n;i++)
{
int j=i+len-1;
for(int k=i;k<j;k++)
{
f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]+(sum[i][k]-sum[k+1][j])*(sum[i][k]-sum[k+1][j]));
}
}
}
cout<<f[1][n]<<endl;
return 0;
}
第三周
第一题
还是考数学的题,只要找到最大公约数,再看每一个数除了最大公约数,1,2和3以外有没有其他的约数,如果还有的话就做不到了。如果没有就OK
#include <bits/stdc++.h>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
int t, n;
const int maxn = 2E5+5;
int arr[maxn];
int main()
{
cin >> t;
while(t--)
{
cin >> n;
int g;
for(int i = 1; i <= n; ++i)
{
cin >> arr[i];
if(i == 1)
{
g = arr[i];
}
else
{
g = __gcd(arr[i], g); //找到所有数字的最大公约数
}
}
int tmp, lef = 0, ans = 1;
for(int i = 1; i <= n; ++i)
{
tmp = arr[i] / g; //直接用arr来存放每个数
while(1)
{
lef = tmp % 2;
if(lef != 0)
{
break;
}
tmp /= 2;
}
lef = 0;
while(1)
{
lef = tmp % 3;
if(lef != 0)
{
break;
}
tmp /= 3;
}
if(tmp != 1)
{
ans = 0;
}
}
cout << (ans? "YES":"NO") << endl;
}
return 0;
}
第二题
这是本周唯一一个相对难一点的题
先上ac code,看上去不很难啊???
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 1E6+6;
char str[maxn]; //默认全0
int last[26], sum;
signed main()
{
cin >> str;
int len = strlen(str);
memset(last, -1, sizeof(last)); //置为-1
for(int i = 0; i < len; ++i)
{
sum += (len-i)*(i-last[str[i]-'a']);
last[str[i]-'a'] = i;
}
cout << sum;
return 0;
}
事实上,这题不适合用前缀和,因为不满足字串分值和的条件,但是枚举26个字母的出现次数又太过麻烦。代码中使用last[i]来标记上一个字母出现的位置。因为字符串下表从0开始所以为了区分是否在初始位置,把last初始化为-1。(len-i)*(i-last[str[i]-'a'])时啥意思呢?当前字串的最大长度乘以当前位置和上一个位置的距离。因为从last[str[i]-'a']+1的位置开始,i位置所在的字母+1的buff才生效,而这个+1的buff对这个位置开始的所有能够碰到i的字串都生效。害,这种感觉就是只可意会不可言传啊!附图
第三题
主要考察对内置数据结构set和map的运用,能用map<int, int>就不要用set<pair<int,int> >了。map对于数对还是比set要好用的。
#include <bits/stdc++.h>
using namespace std;
map<int, int> m1, m2;
int n, op, sum;
int main()
{
cin >> n;
while(n--)
{
cin >> op;
if(op == 1)
{
int w, t;
cin >> w >> t;
if(m1.count(w) == 0 && m2.count(t) == 0)
{
m1[w] = t;
m2[t] = w;
}
}
else if(op == 2)
{
int f = m1.begin()->first, s = m1.begin()->second;
m1.erase(f);
m2.erase(s);
}
else
{
int f = m2.begin()->first, s = m2.begin()->second;
m1.erase(s);
m2.erase(f);
}
}
for(auto x:m1)
{
sum += x.first;
}
cout << sum;
return 0;
}
第四题
水题, 只要排好序然后从后往前找差距就可以了,如果一个差距大于k那么前面的都不可能胜利。可以反向排序这样子就更容易些
#include <bits/stdc++.h>
using namespace std;
int n, k, sum=1;
int main()
{
cin >> n >> k;
vector<int> arr(n);
for(int i = 0; i < n; ++i)
{
cin >> arr[i];
}
sort(arr.begin(), arr.end(), less<int>());
for(int i = n-1; i > 0; --i)
{
if(arr[i]-arr[i-1] <= k)
{
sum++;
}
else
{
break;
}
}
cout << sum << endl;
return 0;
}
第五题
水题*2,真以为我格某不会next_permutation?不过小心输入输出超时!如果想用cin,cout输出的话,快读快写代码如下:
#define endl '\n'
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n, num;
cin >> n;
vector<int> arr;
for(int i = 1; i <= n; ++i)
{
cin >> num;
while(num--)
{
arr.push_back(i);
}
}
do
{
bool flag = 0;
for(int x: arr)
{
if(!flag)
{
printf("%d", x);
flag = 1;
}
else
{
printf(" %d", x);
}
}
printf("\n");
}
while(next_permutation(arr.begin(), arr.end()));
return 0;
}
第六题![](https://i-blog.csdnimg.cn/blog_migrate/b463a7882af28884b08c739c18ebf0d9.png)
水题*3,真以为格某人是面团捏的吗?
#include <bits/stdc++.h>
#define int long long
using namespace std;
int sum;
int n, m, t;
string x;
int chtonum(char c)
{
if(isdigit(c))
{
return c-'0';
}
else if(isupper(c))
{
return c-'A'+10;
}
else if(islower(c))
{
return c-'a'+36;
}
}
char inttoch(int i)
{
if(i < 10)
{
return i+'0';
}
else if(i < 36)
{
return i-10+'A';
}
else
{
return i-36+'a';
}
}
signed main()
{
cin >> n >> m;
while(n--)
{
int num = 0;
cin >> t >> x; //一个t进制数x
while(!x.empty())
{
num = num*t+chtonum(x[0]);
x.erase(x.begin());
}
sum += num;
}
stack<char> s;
while(sum > 0)
{
s.push(inttoch(sum%m));
sum /= m;
}
while(!s.empty())
{
cout << s.top();
s.pop();
}
return 0;
}
第七题![](https://i-blog.csdnimg.cn/blog_migrate/7c6d07c1a267efb9775e00260b72b8a4.png)
水题*4,只需要判断字符串“循环移位”后能不能等于自己就行了。字串的长度可以等于自己的啊
#include <bits/stdc++.h>
using namespace std;
int t;
int main()
{
cin >> t;
while(t--)
{
int n;
string str, str1;
cin >> n >> str;
str1 = str;
reverse(str1.begin(), str1.end());
bool flag = 0;
while(n--)
{
char c = str.back();
str.pop_back();
str = c + str;
if(str == str1)
{
flag = 1;
break;
}
}
if(flag)
{
cout << "YES" << endl;
}
else
{
cout << "NO" << endl;
}
}
return 0;
}
第八题
水题*5,在格某人面前还有哪道题是无尽?主要是判断集合的从属关系,题目的数据量比较小,暴力枚举就可以。
#include <bits/stdc++.h>
using namespace std;
set<int> s[102]; //set集合
bool f[102];
int main()
{
int t;
cin >> t;
for(int i = 1; i <= t; ++i)
{
int n;
cin >> n;
int num;
while(n--)
{
cin >> num;
s[i].insert(num); //集合中加入元素
}
}
for(int i = 1; i <= t; ++i) //对于i集合,要找j集合是否为其子集
{
for(int j = 1; j <= t; ++j)
{
if(j != i && s[j].size() <= s[i].size())
{
bool flag = 1; //s[j]是否为s[i]的子集
for(auto x: s[j])
{
if(s[i].count(x) == 0) //如果有一个没找到就说明不是子集
{
flag = 0;
}
}
if(flag)
{
f[i] = 1;
}
}
}
}
for(int i = 1; i <= t; ++i)
{
if(f[i])
{
cout << "NO" << endl;
}
else
{
cout << "YES" << endl;
}
}
return 0;
}
第九题
emmm,我调了两次没对,就不说是水题了。full的条件是两个都是素数且不相等,partial credit的条件是两个数互质且都是完全平方伪素数,光互质不行,因为有一个数可能自身含有完全平方因子。
#include <bits/stdc++.h>
#define int long long
using namespace std;
bool isprim(int a)
{
int t = sqrt(a);
for(int i = 2; i <= t; ++i)
{
if(a % i == 0)
{
return false;
}
}
return true;
}
bool isff(int a) //是不是ff质数
{
int t = sqrt(a);
for(int i = 2; i*i <= a; ++i)
{
if(a % (i*i) == 0)
{
return false;
}
}
return true;
}
signed main()
{
int a, b;
cin >> a >> b;
bool fa = isprim(a), fb = isprim(b);
if(fa && fb && a != b)
{
cout << "full credit" << endl;
}
else
{
bool ffa = isff(a), ffb = isff(b);
if(ffa && ffb && __gcd(a, b) == 1)
{
cout << "partial credit" << endl;
}
else
{
cout << "no credit" << endl;
}
}
return 0;
}
第十题
本周的boss,我看了一次题解,但是也不算太难。由于题目中的数组是从后往前操作的,因此反向存数组比较好,一次最多可以拷贝前面的所有元素。从第一个开始,找第二个如果和第一个元素相等就加入“等值区块”,否则就把前面的“等值集合”拷贝,并覆盖后面的所有数。每次集合成指数增大。
#include <bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while(t--)
{
int n;
cin >> n;
vector<int> arr(n); //从后往前操作的数组,可以用反向存数组
for(int i = n-1; i >= 0; --i)
{
cin >> arr[i];
}
int now = 1, ans = 0;
while(now < n)
{
if(arr[now] == arr[0])
{
++now;
}
else
{
now *= 2;
ans++;
}
}
cout << ans << '\n';
}
return 0;
}