A-Space Navigation
题目大意:在坐标系中你的初始位置为(0,0)UDRL分别对应向上,向下,向右,向左操作,告诉你目标点位和当前已执行的操作。问能否通过删除部分操作到达目标点。
思路:确定目标点和当前位置,通过这两个坐标来确定要删除的操作及其个数,如果原操作中有对应数量的操作,则可以完成目标,否则不行。
#include <iostream>
#include <cstring>
using namespace std;
string p;
int ox,oy,nx,ny,t,cu,cd,cr,cl;
int main()
{
cin>>t;
while(t--)
{
cin>>ox>>oy; //目标点位
cu=cr=cd=cl=nx=ny=0;
cin>>p;
for(int a=0;a<p.length();a++) //找到当前点位
{
if(p[a]=='U')
{
ny++;
cu++;
}else if(p[a]=='D')
{
ny--;
cd++;
}else if(p[a]=='R')
{
nx++;
cr++;
}else
{
nx--;
cl++;
}
}
bool can=true;
nx-=ox;
ny-=oy;
if(nx>=0) //统计横坐标偏差 ,并判断是否有对应的数目
{
if(cr<nx)can=false;
}else
{
if(cl<-nx)can=false;
}
if(ny>=0) //统计纵坐标偏差 ,并判断是否有对应的数目
{
if(cu<ny)can = false;
}else
{
if(cd<-ny)can = false;
}
cout<<(can?"YES":"NO")<<endl;
}
}
B-New Colony
题目大意:给一个数组代表山的高度,定义一种操作投石头:如果h[i]>=h[i+1]石头就会接着滚下去。否则石头停下来当前的山的高度加一。超出数组的长度后就会加入收集系统,,问第k个石头的位置。
思路:开个数组直接模拟。
#include <vector>
#include <iostream>
#include <cstring>
using namespace std;
int arr[105],n,k,t;
vector<int> ve;
int main()
{
cin>>t;
while(t--)
{
cin>>n>>k;
for(int a=1;a<=n;a++)cin>>arr[a];
for(int a=0;a<k;a++)//模拟过程
{
int b=1;
for(b=1;b<=n;b++)
{
if(b==n)
{
b=-1;
break;
}else
{
if(arr[b]<arr[b+1])
{
arr[b]++;
break;
}
}
}
if(a==k-1)
{
cout<<b<<endl;
break;
}
if(b==-1)
{
cout<<b<<endl;
break;
}
}
}
}
C-Fence Painting
题目大意:你有n块篱笆,第i块的颜色是ai,你想要的重新粉刷,粉刷后第i块是bi。你邀请m个画家来画,第i个画家按顺序到,同时一个画家可以把一个篱笆染成一个对应的颜色(不能拒绝,每个画家必须画一个篱笆),第i个画家的颜色是ci。问:你能否把篱笆染成目标效果。
思路:颜色可以被染色,对于不被需要的颜色:假设第i个画家的颜色被第j块篱笆需要,那么把在他之前的不被需要的颜色都涂到j去等着被他染掉就好了。所以从后往前遍历画家,如果当画家被需要就安排到对应的位置去,如果不被需要,就填图到i+1画家的位置就好了。注意处理不需要更改颜色的情况(我通过预先找到与最后一个画家颜色相同的篱笆 来处理)。
#include <iostream>
#include <map>
#include <vector>
using namespace std;
const int maxx = 100005;
vector<int> cind[maxx];
map<int,int> change;
int t,m,n,ai[maxx],bi[maxx],ci[maxx],ind[maxx],allneed=0;
int main()
{
cin>>t;
while(t--)
{
change.clear();
allneed=0;
for(int a=0;a<maxx;a++)
{
cind[a].clear();
ind[a]=0;
}
cin>>n>>m;
for(int a=1;a<=n;a++)
{
cin>>ai[a];
}
for(int a=1;a<=n;a++)
{
cin>>bi[a];
if(bi[a]!=ai[a])
{
change[bi[a]]++; //表示要改为bi[a]的颜色的篱笆的数量
allneed++; //总共要改颜色的篱笆的数量
cind[bi[a]].push_back(a); //把要改为bi[a]的颜色的篱笆的位置存起来
}
}
for(int a=1;a<=m;a++)
{
cin>>ci[a];
}
for(int a=1;a<=n;a++) //找到可以涂最后一个篱笆的画家
{
if(bi[a] == ci[m])
{
ind[m+1] = a;
break;
}
}
for(int a=m;a>0;a--)
{
if(change[ci[a]]>0) //如果这一个画家的颜色是被需要的那么就把他涂到对应位置去。
{
ind[a] = cind[ci[a]].back(); //填入位置
cind[ci[a]].pop_back(); //删除已被填了的位置
change[ci[a]]--; //减少标记 和 待填图数
allneed--;
}else //如果不得需要就 把他填图到 会被后面画家染色的位置上
{
ind[a] = ind[a+1];
}
}
if(ind[m] && allneed==0) //如果最后一个篱笆被涂上了,并且没有待填图的篱笆就成功了
{
cout<<"YES"<<endl;
cout<<ind[1];
for(int a=2;a<=m;a++)
{
cout<<" "<<ind[a];
}
cout<<endl;
}else //否则失败
{
cout<<"NO"<<endl;
}
}
}
D-AB Graph
题目大意:给你一个有向图由n个点组成,任意两点之间都有来回路,且被标记为a或b,找出路径序列为回文串(左右对称)其长度为m的访问方式。
思路:只有路径标记只有a和b是关键。如果m为奇数直接找两个点来回走就好了,如果m为偶数:首先是一个特殊情况如果n==2那么1->2和2->1标记一定要相同不不然无解;在n>2时:找到三个点满足(ma[a][b] == ma[c][a] && ma[b][a]== ma[a][c])
(c和b可以是一个点),如果m/2为奇数那么序列是:b->a->b…->a->c->a…->c;如果m/2为偶数那么序列是:a->b->a…->a->c->a…->a
#include <iostream>
#include <cstring>
using namespace std;
const int maxx = 1005;
int t,n,m,ma[maxx][maxx];
string tmp;
int main()
{
cin>>t;
while(t--)
{
cin>>n>>m;
for(int a=1;a<=n;a++)
{
cin>>tmp;
for(int b=1;b<=n;b++)
ma[a][b]=tmp[b-1];
}
if(n==2 && m%2==0) //处理特殊情况
{
if(ma[1][2] == ma[2][1])
{
cout<<"YES"<<endl;
cout<<1;
for(int a=0;a<m;a++)
{
cout<<" "<<(a%2==0?2:1);
}
cout<<endl;
}else
{
cout<<"NO"<<endl;
}
continue;
}
if(m%2==1) //m为奇数时
{
cout<<"YES"<<endl;
cout<<1;
for(int a=0;a<m;a++)
{
cout<<" "<<(a%2==0?2:1);
}
cout<<endl;
}else //偶数时
{
int p1=0,p2=0,p3=0;
for(int a=1;a<=n;a++) //开三层for暴力找点 a!=b,c 但是b可以等于c
{
for(int b=1;b<=n;b++)
{
if(a==b)continue;
for(int c=1;c<=n;c++)
{
if(a==c )continue;
if(ma[a][b] == ma[c][a] && ma[b][a]== ma[a][c])
{
p1 = a;
p2 = b;
p3 = c;
break;
}
}
if(p1)break;
}
if(p1)break;
}
if(p1) //输出序列
{
cout<<"YES"<<endl;
if(m/2%2==0)
{
cout<<p1;
for(int a=0;a<m/2;a++)
{
cout<<" "<<(a%2==0?p2:p1);
}
for(int a=0;a<m/2;a++)
{
cout<<" "<<(a%2==0?p3:p1);
}
cout<<endl;
}else
{
cout<<p2;
for(int a=0;a<m/2;a++)
{
cout<<" "<<(a%2==0?p1:p2);
}
for(int a=0;a<m/2;a++)
{
cout<<" "<<(a%2==0?p3:p1);
}
cout<<endl;
}
}else
{
cout<<"NO"<<endl;
}
}
}
}
E-Sorting Books
题目大意:给一个数组每次可以把其中一个数移到最后,问最少移动几次可以是所有的相同的数字相邻。
思路:把问题转化为从怎么移动可以让最多的数字不动。规定几个数字R[i]从表示数字i的最靠右的位置,L[i]表示i最靠左的位置,cnt[i]表示从当前位置向后数字i的个数,book[i]用来存储原数组。从后向前看,dp[i]代表从i开始向后想序列中最后可以让几个数字不动来实现效果。对于第i个数字,分两种情况:1、这个这个数字不是这一种数字中最靠左的,那么就让当前出现次数最多的数字保持不动dp[i]=max( dp[i+1],cnt[ book[i] ] )。2、这个数字是这一种数字中最靠左的,此时如果让这一种数字都不动那么可以不动的数字的数量就是cnt[ book[i] ]+dp[ R[ book[i] ] ] , 如果让这一种数字移动可以保持不动的最大数量就是dp[i+1]。
#include <iostream>
#include <cstring>
using namespace std;
const int maxx = 500005;
int L[maxx],R[maxx],dp[maxx],cnt[maxx],book[maxx],n;
int main()
{
cin>>n;
for(int a=1;a<=n;a++)
{
cin>>book[a];
if(!L[book[a]])
{
L[book[a]] = a;
}
R[book[a]] = a;
}
memset(dp,0,sizeof(dp));
for(int a = n;a>0;a--)
{
cnt[book[a]]++;
if(a == L[book[a]])
{
int re = cnt[book[a]]+dp[R[book[a]]+1];
int mo = dp[a+1];
dp[a] = max(re,mo);
}else
{
int re = cnt[book[a]];
int mo = dp[a+1];
dp[a] = max(re,mo);
}
}
cout<<n-dp[1]<<endl;
}