传送门
题目大意:
给定一个字符串,你可以给任意位置插入一个‘a’,
如果可以使字符串不为回文串,那么输出YES并输出
任意满足的情况
如果不可以,输出NO
思路:
如果字符串全为a,则输出NO
否则输出YES.
从左到右直到第一个不为a找左边有多少个a,记为l,
从右到左直到第一个不为a找右边有多少个a,记为r
如果l == r ,则将a加在字符串末尾
否则,将a加在字符串a多的那一边
代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define IO ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
void slove()
{
string s;
cin >> s;
bool ans = false;
int left = 0,right = 0;
for(int i = 0;i < s.length();++i){
if(s[i] != 'a') {
ans = true;
left = i+1;
break;
}
}
if(!ans) cout << "NO" << endl;
else {
for(int i = s.length()-1;i >= 0;--i){
if(s[i] != 'a') {
right = s.length() - i;
break;
}
}
if(left == right) s+='a';
else if(left > right) s = 'a' + s;
else s = s + 'a';
cout << "YES" << endl;
cout << s << endl;
}
}
int main()
{
IO;
int t;
cin >> t;
while(t--){
slove();
}
return 0;
}
题目总结:
思维水题,确定思维证明无误后,再顺畅的敲代码,
这不仅是一种成功,更是一种享受
传送门
题目大意:
给定a,b两个字符串
如果a的前n个字符满足0的个数和1的个数相等
则可以将a的前n个字符0->1和1->0
可以进行任意此操作,判断是否可以将a变成b
思路:
从后往前,我们从第一个不相等的位置将a字符串前部翻转
翻转之后,接着往前找相等的位置将字符串a前部翻转
重复前两个操作,直到结束
注意特判结束的情况
主要记录判断每次字符串是否可以翻转
代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define IO ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
void slove()
{
int n;
cin >> n;
string s1,s2;
cin >> s1 >> s2;
int l1=0,r1=0,l2=0,r2=0;
for(int i = 0;i < s1.length();++i){
if(s1[i] == '0') l1++;
else r1++;
if(s2[i] == '0') l2++;
else r2++;
}
if(l1 != l2){
cout << "NO" << endl;
return ;
}
bool ans = false,sign = true;
for(int i = s1.length()-1;i >= 0 && sign;--i){
if(!ans){
if(s1[i] == s2[i]){
if(s1[i] == '0') l1--;
else r1--;
}
else {
ans = true;
if(l1 == r1) {
if(s1[i] == '0') l1--;
else r1--;
}
else sign = false;
}
}
else {
if(s1[i] != s2[i]){
if(s1[i] == '0') l1--;
else r1--;
}
else {
ans = false;
if(l1 == r1) {
if(s1[i] == '0') l1--;
else r1--;
}
else sign = false;
}
}
}
if(sign) cout << "YES" << endl;
else cout << "NO" << endl;
}
int main()
{
IO;
int t;
cin >> t;
while(t--){
slove();
}
return 0;
}
题目总结:
思维中等题,从后往前遍历是一个比较常用的思路。
这个题虽然没有用到前缀和,但是和前缀和有一些相像的地方。
比如:记录从前到翻转位置0,1的数量
传送门
题目大意:
给定一个01串,
我们来构造左右括号的匹配情况,
如果可以出现两种左右括号情况
使得1对应的位置相等
使得0对应的位置不相等
那么输出YES并输出那两种情况
否则输出NO
思路:
如果0字符的个数为偶数或者第一个或最后一个字符为0则输出NO
否则输出YES
这时候我们确定了第一个位置和最后一个位置是1。
令它们分别为()
然后对于剩余1我们进行一左一右的编码,对于0进行一左一右编码
第二种情况1进行一左一右编码,对于0进行一右一左编码
那么它们一定满足上面的情况
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define IO ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
void slove()
{
int n;
cin >> n;
string s;
cin >> s;
int nm = 0;
for(int i = 0;i < s.length();++i) if(s[i] == '0') nm++;
if(nm%2 != 0 || s[n-1]=='0' || s[0]=='0') {
cout << "NO" << endl;
return ;
}
cout << "YES" << endl;
bool l1=true,r1=true;
cout << '(';
for(int i = 1;i < s.length()-1;++i){
if(s[i] == '1') {
if(l1) cout << '(';
else cout << ')';
l1 = !l1;
}
else {
if(r1) cout << '(';
else cout << ')';
r1 = !r1;
}
}
cout << ')' << endl;
l1=true,r1=false;
cout << '(';
for(int i = 1;i < s.length()-1;++i){
if(s[i] == '1') {
if(l1) cout << '(';
else cout << ')';
l1 = !l1;
}
else {
if(r1) cout << '(';
else cout << ')';
r1 = !r1;
}
}
cout << ')' << endl;
}
int main()
{
IO;
int t;
cin >> t;
while(t--){
slove();
}
return 0;
}
题目总结:
思维拐弯题,如果我们注意力集中在一左一右的匹配那就进入死胡同了
这时候我们的思维指向10的区分处理,也就是“分治”思想,
那这个题就豁然开朗了,1处理自己的,0处理自己的
化繁为简,大道使然
传送门
题目大意:
用不超过三种颜色填满n*n的格子使得相邻的格子颜色不同。
交互题,一个输出立马给出一个结果
Alice给出一个颜色,然后使用不是这个颜色的颜色去填空格
输出颜色和位置
思路:
我们用两个队列将所有格子空开,用1,2分别去填满其中一种再用3去填没满的队列。当其中一个队列填满剩下未填满的格子都是隔开的用3去填不会出现任何问题
#include<iostream>
#include<vector>
using namespace std;
#define IO ios::sync_with_stdio(0),cin.tie(0)
#define LL long long
LL n;
vector<LL> A,B;
void slove()
{
cin >> n;
for(int i = 0;i < n;++i){
for(int j = 0;j < n;++j){
if((i+j)%2 == 0)
A.push_back(i*n+j);
else
B.push_back(i*n+j);
}
}
LL x = A.size();
LL y = B.size();
LL p = 0;
LL q = 0;
LL a;
for(int i = 0;i < n*n;++i){
cin >> a;
if(p < x && q < y){
if(a == 1){
cout << 2 << " " << B[q]/n+1 << " " << B[q]%n+1 << endl;
q++;
}
else {
cout << 1 << " " << A[p]/n+1 << " " << A[p]%n+1 << endl;
p++;
}
}
else if(p == x){
if(a == 2) {
cout << 3 << " " << B[q]/n+1 << " " << B[q]%n+1 << endl;
q++;
}
else {
cout << 2 << " " << B[q]/n+1 << " " << B[q]%n+1 << endl;
q++;
}
}
else {
if(a == 1){
cout << 3 << " " << A[p]/n+1 << " " << A[p]%n+1 << endl;
p++;
}
else {
cout << 1 << " " << A[p]/n+1 << " " << A[p]%n+1 << endl;
p++;
}
}
}
}
int main()
{
IO;
slove();
}
题目总结:
第一次做交互题,没有接触经验,导致考虑的时候漏洞百出。
没有良好的思维变化。对于交互题可以理解成出错处理来思考。
例如队列填满了,填不了了就出错了,填副对角线,副对角线怎么填,用3来填。
传送门
题目大意:
每个城市有一个ai和ci
从第i个城市到第j个城市需要花费
max(a[j],a[i]-a[j])
问从第一个城市出发回到第一个城市的最小花费
旅行商问题
思路:
我们走一圈至少花费c[i]的总和
然后排序补齐a[j]-a[i]-c[i]的花费
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int maxn = 1e5+5;
struct stu{
LL l,r;
}a[maxn*2];
bool cmp(struct stu a,struct stu b)
{
if(a.l == b.l) return a.r < b.r;
else return a.l < b.l;
}
int main()
{
int n;
cin >> n;
for(int i = 1;i <= n;++i) cin >> a[i].l >> a[i].r;
sort(a+1,a+n+1,cmp);
// for(int i = 1;i <= n;++i) cout << a[i].l << " " << a[i].r << endl;
LL sum = 0;
for(int i = 1;i <= n;++i) sum+=a[i].r;
LL naj = a[1].l+a[1].r;
for(int i = 2;i <= n;++i){
if(naj < a[i].l){
sum += (a[i].l - naj);
}
naj = max(naj,a[i].l+a[i].r);
}
cout << sum << endl;
return 0;
}
题目总结:
思维题转换题,要对于题意有一定的理解
大胆猜测,小心检验
传送门
题目大意:
左边从小到大,右边从大到小
每行数据符合l[i],r[i]的位置上相同
思路:
无:
#include<bits/stdc++.h>
using namespace std;
int n;
int a[200000+20],b[200000+20];
int ano[200000*2+20];
bool is[200000*2+20];
bool bad[200000*2+20];
pair<int,int> gao(int l,int r,int &val)
{
val = !is[l];
int l_,r_;
l_ = l,r_ = ano[l];
int prel=l,prer=ano[l];
bad[ano[l]] = 1;
r += 1;
while(l < l_ || r > r_)
{
if(l < l_){
while(l < l_){
++l;
if(!bad[l]){
val += !is[l];
if(ano[l] > prer){
return make_pair(-1,-1);
}
bad[ano[l]] = 1;
prer = ano[l];
}
}
if(prer < l_) return make_pair(-1,-1);
r_ = prer;
}
else{
while(r > r_){
--r;
if(!bad[r]){
val += !is[r];
if(ano[r] < prel){
return make_pair(-1,-1);
}
bad[ano[r]] = 1;
prel = ano[r];
}
if(prel > r_)
return make_pair(-1,-1);
l_ = prel;
}
}
}
return make_pair(l_,r_);
}
int slove(int A,int B)
{
if(A > B) return 0;
int z = 0;
pair<int,int> seg = gao(A,B,z);
if(seg.first == -1) return -1;
int cnt = B-seg.second+1+seg.first-A+1;
int tmp = slove(seg.first+1,seg.second-1);
if(tmp == -1) return -1;
return tmp+min(cnt/2-z,z);
}
int main()
{
cin >> n;
for(int i = 1;i <= n;++i){
cin >> a[i] >> b[i];
ano[a[i]] = b[i];
ano[b[i]] = a[i];
is[a[i]] = 1;
}
cout << slove(1,n+n) << endl;
return 0;
}