8.8?不可能的,刺客信条真好玩
Codeforces 1550B 题目链接:点击这里传送
题意:
你每次可以删除一个子串,他的元素必须为同一个数。这样删除一次的得分是 a
×
\times
×len+b。现输出删光所有元素后最大的得分总和。
思路:
不用管a,因为都得删光。对于b,如果是负数,那么就让删的次数尽可能少,如果是正数,就一个个删。
#include<bits/stdc++.h>
using namespace std;
int t,n,cnt;
string s;
int a, b;
int ansa, ansb;
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> t;
while (t--)
{
cin >> n>> a >> b;//a*len+b
cin >> s;
ansa = a * n;
cnt = 1;
for (int i = 1; i < s.length(); i++)
{
if (s[i] != s[i - 1]) cnt++;//组数
}
ansb = max(n * b, (cnt /2+1) * b);
cout << ansa + ansb << endl;
}
return 0;
}
Codeforces 1547A 题目链接:点击这里传送
题意:
给出A和B的坐标,再给出一个障碍物F的坐标,求A到B最小的曼哈顿距离
思路:
特判A和B在一条直线上并且F在AB中间的情况即可。
#include<bits/stdc++.h>
using namespace std;
int t;
int ax, bx, fx;
int ay, by, fy;
int dx, dy;
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> t;
while (t--)
{
cin >> ax >> ay; cin >> bx >> by; cin >> fx >> fy;
dx = abs(ax - bx);
dy = abs(ay - by);
if (dx == 0&&fx==ax)//在同一条线上
{
int mins = min(ay, by);
int maxs = max(ay, by);
if (fy >= mins && fy <= maxs)//挡住了
{
cout << 2 + dy << endl;
}
else cout << dy << endl;
continue;
}
if (dy == 0&&fy==ay)
{
int mins = min(ax, bx);
int maxs = max(ax, bx);
if (fx >= mins && fx <= maxs)
{
cout << 2 + dx << endl;
}
else cout << dx << endl;
continue;
}
cout << dx + dy << endl;//曼哈顿距离
}
return 0;
}
Codeforces 1546A 题目链接:点击这里传送
题意:
给你两个数组,要求你把A数组变得和B数组完全一样。你只有一种操作,选择两个数
a
i
a_i
ai和
a
j
a_j
aj,使
a
i
a_i
ai-1并使
a
j
a_j
aj+1。如果可行,输出操作次数和操作顺序,如果不行输出-1。
思路:
定义两个cnt,一个为需要加的次数,一个为需要减的次数,只有两个相同时才合法。
记录cnt的同时开两个数组,把需要加的数的编号和需要减的数的编号记录下来。
#include<bits/stdc++.h>
using namespace std;
#define MAXN 105
int a[MAXN];
int b[MAXN];
vector <int> add;
vector <int> del;
int t,n;
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> t;
while (t--)
{
cin >> n;
add.clear();
del.clear();
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i <= n; i++) cin >> b[i];
for (int i = 1; i <= n; i++)
{
if (a[i] < b[i])//需要增加
{
for (int j = 1; j <= b[i] - a[i]; j++)
{
add.push_back(i);
}
}
if (a[i] > b[i])//需要减小
{
for (int j = 1; j <= a[i] - b[i]; j++)
{
del.push_back(i);
}
}
}
if (del.size() != add.size())
{
cout << -1 << endl;
continue;
}
cout << add.size() << endl;
for (int i = 0; i < add.size(); i++)
{
cout << del[i] << " " << add[i] << endl;
}
}
return 0;
}
Codeforces 1546B 题目链接:点击这里传送
题意:
先给出n个字符串,再给出n-1个字符串。在这n-1个字符串中,每个字符串的相同位置的字符可能被打乱了,要求你输出把这n-1个字符串复原后少的那一个字符串。
思路:
别想着如何还原,定义一个二维数组记录每个位置下每个字母出现的个数。前n个字符串遍历的时候加,后n-1个字符串遍历的时候减,最后把每位上剩余的那个字符输出就行。
#include<bits/stdc++.h>
using namespace std;
#define MAXN 100005
int t, n,m;
int cnt[MAXN][30];//在每个位置出现的字符数量
string ans;
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> t;
while(t--)
{
cin >> n >> m;
string temp;
ans = "";
memset(cnt, 0, sizeof(cnt));
for(int i=1;i<=n;i++)
{
cin >> temp;
for (int j = 0; j < m; j++) cnt[j][temp[j] - 'a']++;
}
for (int i = 1; i < n; i++)
{
cin >> temp;
for (int j = 0; j < m; j++) cnt[j][temp[j] - 'a']--;
}
for (int i = 0; i < m; i++)
{
for (int j = 0; j < 30; j++)
{
if (cnt[i][j] > 0) ans += (char)'a' + j;
}
}
cout << ans << endl;
}
return 0;
}
Codeforces 1547B 题目链接:点击这里传送
题意:
构造一个字符串。按照字母表的顺序(abcd…),构造规则是把当前的字符添加到字符串的后面或添加到字符串的前面。先给出一个字符串,问有没有可能构造出来该字符串。
思路:
模拟字符添加的过程,用双指针来维护模拟时的左右边界。如果左边界-1或者右边界+1不为字母表的下一个字符,宣告非法退出程序。
#include<bits/stdc++.h>
using namespace std;
int t;
string s;
int p1, p2;
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> t;
while (t--)
{
cin >> s;
p1 = -1; p2 = -1;
for (int i = 0; i < s.length(); i++)
{
if (s[i] == 'a')
{
p1 = min((int) s.length()-1,i+1);
p2 = max(0,i-1);
break;
}
}
if (p1 == -1)
{
cout << "NO" << endl;
continue;
}
int cnt = 1;//已经出现了几个字母
while (cnt < s.length())
{
if (s[p1] == (char)'a' + cnt)
{
cnt++;
p1++;
}
else if (s[p2] == (char)'a' + cnt)
{
cnt++;
p2--;
}
else//没找到
{
break;
}
}
if (cnt == s.length()) cout << "YES" << endl;
else cout << "NO" << endl;
}
return 0;
}
Codeforces 1547C 题目链接:点击这里传送
题意:
给出一个文件的行数和两个操作指令数组。
当操作指令为0时,换行,否则就在第a[i]行上修改文件。
现要求在保证a数组和b数组各自元素之间不发生相对变化的情况下组成一个新的操作指令数组。若可能,输出这个操作指令数组;若不可能,输出-1.
思路:
类似于贪心。把0尽可能多的放进去,使得行数尽可能增大。所谓不可能的情况,就是对大于当前最大行数的某一行进行修改操作。如果某一刻,
a
i
a_i
ai和
b
i
b_i
bi均不为0且
a
i
a_i
ai和
b
i
b_i
bi均大于当前最大行数,输出-1。
#include<bits/stdc++.h>
using namespace std;
int n, m, k;
int a[310], b[310];
int main() {
int t;
scanf("%d", &t);
getchar();
while (t--) {
queue<int> q;
scanf("%d %d %d", &k, &n, &m);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
for (int i = 1; i <= m; i++)
scanf("%d", &b[i]);
int i = 1, j = 1;
bool st = true;
while (i + j != n + m + 2) {
if (i <= n && a[i] == 0) {
q.push(0);
i++;
k++;
continue;
}
if (j <= m && b[j] == 0) {
q.push(0);
j++;
k++;
continue;
}
if (i <= n && a[i] <= k) {
q.push(a[i]);
i++;
continue;
}
if (j <= m && b[j] <= k) {
q.push(b[j]);
j++;
continue;
}
st = false;
break;
}
if (st) {
while (!q.empty()) {
int t = q.front();
q.pop();
printf("%d ", t);
}
printf("\n");
} else
printf("-1\n");
}
return 0;
}
Codeforces 1547D 题目链接:点击这里传送
题意:
如果一个数组中
a
i
a_{i}
ai&
a
i
+
1
a_{i+1}
ai+1=
a
i
a_i
ai,那么就称这个数组是growing的。
现在给你一个数组a,要求你构造出一个数组b,使得由
a
i
a_i
ai
⨁
\bigoplus
⨁
b
i
b_i
bi构成的数组是growing的
思路:
看起来唯一的突破点是
b
1
b_1
b1=0
在根据题目条件将
a
i
a_i
ai
⨁
\bigoplus
⨁
b
i
b_i
bi定义为
c
i
c_i
ci,这样我们就可提炼出以下方程式:
c
i
c_i
ci&(
a
i
+
1
a_{i+1}
ai+1
⨁
\bigoplus
⨁
b
i
+
1
b_{i+1}
bi+1)=
c
i
c_i
ci
提取模型:x&(y
⨁
\bigoplus
⨁z)=x ,要求构造出尽可能小的y (为方便说明,以下计算过程均已二进制为过程)
当x为1时,y和z要不相同,即z为0,y为1;z为1,y为0;
当x为0时,y和z无所谓,即y为0。(尽可能小)
由此可见y=x&(x
⨁
\bigoplus
⨁z)
即
b
i
b_{i}
bi =(
a
i
a_{i}
ai
⨁
\bigoplus
⨁
b
i
b_{i}
bi)&[(
a
i
a_{i}
ai
⨁
\bigoplus
⨁
b
i
b_{i}
bi)
⨁
\bigoplus
⨁
a
i
+
1
a_{i+1}
ai+1]
现在
a
i
a_i
ai和
a
i
+
1
a_{i+1}
ai+1已知,
b
1
b_1
b1为0,还在等什么呢
#include<bits/stdc++.h>
using namespace std;
int n;
long long s[200010];
/**
1
4
1 2 4 8
**/
int main() {
int t;
scanf("%d", &t);
while (t--) {
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%lld", &s[i]);
printf("0 ");
for (int i = 1; i < n; i++) {
long long a = s[i], b = s[i + 1];
long long j = 1, cnt = 0;
while (b > 0 || a > 0) {
if (b % 2 == 0 && a % 2 == 1)
cnt += j;
//cout << cnt << ' ';
//cout << a << ' ' << b << endl;
j *= 2;
b /= 2;
a /= 2;
}
s[i + 1] += cnt;
printf("%lld ", cnt);
}
printf("\n");
}
return 0;
}
红酒哥比赛的A题 题目链接:点击这里传送
题意:
若一个数组中有一堆连续存在的元素,那么贡献为最小的元素的编号。求这个数组的贡献和。
思路:
正常模拟,注意一下上界。
#include<bits/stdc++.h>
using namespace std;
#define MAXN 90005
int a[MAXN];
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int n;
long long ans = 0;
cin >> n;
for (int i = 1; i <= n; i++)
{
int temp;
cin >> temp;
a[temp]++;
}
int i = 1;
int j;
while(i<=90000)
{
if (a[i] > 0)
{
for (j = i + 1; a[j] != 0; j++)
{
a[j] = 0;
}
ans += i;
}
i++;
}
cout << ans;
return 0;
}
红酒哥比赛的B题 题目链接:点击这里传送
题意:
要求你构造出一个答案,使得学生们的最低分成绩最高。
思路:
最多就10个题目,也就1024种组合,暴力搜索+比较记录最低分就行。
#include<iostream>
#include<algorithm>
using namespace std;
char ans[11];
char s[1010][13];
int n;
int mmin=0;
void dfs(int k,int p)//p表示层数
{
if(p>k)
{
int Min=100;
for(int i=0;i<n;i++)
{
int sum=0;
for(int j=1;j<=k;j++)
{
if(ans[j]==s[i][j])
sum++;
}
Min=min(sum,Min);//这一种情况下得到的最低分
}
mmin=max(mmin,Min);//全部情况下最低分中的最高分
}
else
{
for(int i=0;i<=1;i++)
{
if(i==0)
ans[p]='T';
else
ans[p]='F';
dfs(k,p+1);
}
}
}
int main()
{
int k;
cin>>n>>k;
for(int i=0;i<n;i++)
for(int j=1;j<=k;j++)
cin>>s[i][j];
dfs(k,1);
cout<<mmin;
return 0;
}
红酒哥比赛的Q题 题目链接:点击这里传送
题意:
给出一些数,求有几个集合(集合个数
≥
\geq
≥ 3)使得集合内的任意三个元素可以组成一个三角形。
思路:
排序后先确定两条边,在求出以这两条边为短边存在的长边的最大值。设这之间有m条边,根据数学规律(鬼知道咋来的),集合个数为
2
n
2^n
2n-1。
n
2
n^2
n2复杂度枚举下来累加。
#include<bits/stdc++.h>
using namespace std;
#define MAXN 55
int a[MAXN];
int n;
long long ans;
long long quickpow(long long a, long long m)
{
long long temp = 1;
while (m)
{
if (m % 2 == 0)
{
a = a * a;
m /= 2;
}
else
{
temp = temp * a;
m--;
}
}
return temp;
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
sort(a + 1, a + 1 + n);
//for (int i = 1; i <= n; i++) cout << a[i] << " ";
//cout << endl;
for (int i = 1; i <= n; i++)
{
for (int j = i+1; j <= n; j++)//两边之和大于第三边
{
int k=j+1;
while (a[i] + a[j] > a[k]&&k<=n) k++;
k--;
long long temp = k - j;
//cout << a[i] << " " << a[j] << " " << a[k] << " " << temp << endl;
ans += quickpow(2, temp) - 1;
}
}
cout << ans;
return 0;
}
红酒哥比赛的Z题 题目链接:点击这里传送
题意:
给出n和一串字符串,这串字符串是1到n的递增排列,但是其中少了一个数,要求你把少的数找出来。
思路:
对于中途出现了非法的情况写法还是很多的,可以直接找,也可以截子串和提前打好的表进行比对。但是如果少的是n就意味着这个字符串是合法的(至少程序认为是),就不会输出任何数。这个特判额外注意下。
#include<bits/stdc++.h>
using namespace std;
int n;
string s;
int a[105];
string ans[105];
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int cnt = 1;
int step = 1;
int pos = 1;
cin >> n;
cin >> s;
for (int i = 1; i <= 100; i++)
{
ans[i] = to_string(i);
}
for (int i = 0; i < s.length(); i += pos)
{
string temp = s.substr(i, step);
if (temp != ans[cnt])
{
cout << cnt;
return 0;
}
cnt++;
if (cnt == 10) step = 2;
if (cnt == 11) pos = 2;
if (cnt == 100) step = 3;
if (cnt == 101) pos = 3;
}
cout << n;
return 0;
}
红酒哥比赛的AB题 题目链接:点击这里传送
题意:
一共有n个评委,他们最高能打3分,最低能打-3分,现已给出m个评委的成绩,让你求现阶段可能的最高分和最低分
思路:
懒得逼逼
#include<bits/stdc++.h>
using namespace std;
double n, m;
double a[105];
int main()
{
//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> n >> m;
double max_val = n * 3-0.0;
double min_val = n * (-3)-0.0;
for (int i = 1; i <= m; i++)
{
double temp;
cin >> temp;
temp /= 1.0;
max_val = max_val - (3 - temp);
min_val = min_val + (temp + 3);
}
printf("%lf %lf", min_val / n + 0.0, max_val / n + 0.0);
return 0;
}
红酒哥比赛的AC题 题目链接:点击这里传送
题意:
给你一个字符串,你可以选择将两个任意字符交换,也可以不换,这叫一次操作。现根据给出的字符串,若一个人背着你做出了一次操作,你是否一定能察觉
思路:
判断字符串有没有重复字符
#include<bits/stdc++.h>
using namespace std;
string s;
set <char> ss;
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> s;
for (int i = 0; i < s.length(); i++)
{
ss.insert(s[i]);
}
if (ss.size() == s.length()) cout << 1;
else cout << 0;
return 0;
}
牛客11258H 题目链接:点击这里传送
题意:
找出有几个三元组(i,j,k)满足
a
i
a_i
ai
×
\times
×
a
j
a_j
aj=
a
k
a_k
ak
思路:
预处理记录下每个数出现的次数。枚举(1,
n
\sqrt{n}
n),再枚举他们的倍数,如果i和i*j都存在,那么加上2
×
\times
×cnt[i]
×
\times
×cnt[j]
×
\times
×cnt[i
×
\times
×j]。(i和j可以互换,另一种情况不会被记录下来)。记得特判一下平方数的不用乘2。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define MAXN 1000005
int cnt[MAXN];
ll ans;
void solve()
{
for (int i = 1; i <= 1000; i++)
{
if (cnt[i] > 0)
{
for (int j = i; j <= 1000000 / i; j++)
{
if (cnt[i * j] > 0)
{
if (i == j)
ans += cnt[i] * cnt[j] * cnt[i * j];//i和j是同一个数
else
ans += cnt[i] * cnt[j] * cnt[i * j] * 2;//i和j交换
}
}
}
}
cout<<ans;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int n;
cin >> n;
for (int i = 1; i <= n; i++)
{
int temp;
cin >> temp;
cnt[temp]++;
}
solve();
return 0;
}
牛客11258I 题目链接:点击这里传送
题意:
给出两个数x和s,令y满足x|y=s,求可能的y的数量。
思路:
四种情况讨论下来
- x=0 s=0 y只能为0,无贡献
- x=0 s=1 y只能为1,无贡献
- x=1 s=0 非法情况
- x=1 s=1 y既可以为1也可以为0,两种情况。
只需记录下4的情况为m种,求 2 m 2^m 2m的值。若出现了3这种情况,直接退出程序输出0。
#include<bits/stdc++.h>
using namespace std;
long long x,y;
int cnt=0;
string get_string(long long n)
{
string ans="";
while(n)
{
if(n%2==1) ans='1'+ans;
else ans='0'+ans;
n/=2;
}
return ans;
}
long long quickpow(long long a,long long n)
{
long long ans=1;
while(n)
{
if(n%2==0)
{
a=a*a;
n/=2;
}
else if(n%2==1)
{
n--;
ans=ans*a;
}
}
return ans;
}
int main()
{
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>x>>y;
string a=get_string(x);//x 为0s为1 一种 为1s为0非法 为0为0一种 为1为1两种
string b=get_string(y);//s
int delta=a.length()-b.length();
if(delta<0) delta=-delta;
if(a.length()<b.length())
{
for(int i=1;i<=delta;i++) a="0"+a;
}
else if(a.length()>b.length())
{
for(int i=1;i<=delta;i++) b="0"+b;
}
// cout<<a<<endl<<b<<endl;
for(int i=0;i<a.length();i++)
{
if(a[i]=='1'&&b[i]=='0')
{
cout<<0;
return 0;
}
if(a[i]=='1'&&b[i]=='1')
{
cnt++;
}
}
if(x==y) cout<<quickpow(2,cnt)-1;
else cout<<quickpow(2,cnt);
return 0;
}