链接
http://codeforces.com/contest/1481
A. Space Navigation
(rating : 800)
题意:一个机器人要从坐标系上的(0,0)走到(i,j) 。 给一串由u,d,l, r (上下左右)组成的字符串代表初始设定的走法。问能否通过删去一些字符,让机器人能成功地走到(i,j),输出 yes or no 。
思路:从(0,0)到(i,j),就是横着走 i步 ,纵着走j步。 只需要判断下 l 和 r 的数目能否凑出 i , u 和 d 的数目能否凑出j 即可。
B. New Colony
(rating: 1100)
题意:现在有一排山,高度为h1,h2,h3 … hn 。把一个石头放在第一座山上 , 如果当前第i座山的高度不小于第i+1座山的高度 , 那么石头就会滚到第i+1座山上;否则,石头会留在第i座山上,并使第i座山高度+1 。当石头滚到最后一座山时,会自动滑落并消失 。 问 : 现在依次放上 k 个石头,第k个石头会滑到第几座山上 。
思路:按题目要求模拟即可 。 当第i座山高度等于第i+1座山时,把它们看成一个整体 , 接着向后遍历 。 当第i座山高度小于第i+1座时 , 该山就会被一直垫高直到石头用完 或者 高度 = min(h[i-1],h[i+1]) 。
C. Fence Painting
(rating:1600)
题意:有n面墙,它们的颜色是 a1, a2, a3 … an 。 但是户主希望它们的颜色是 b1,b2,b3 … bn 。
现在有m位粉刷匠以时间顺序前来 , 每人带着一个油漆桶 ,颜色是 c1,c2, c3 … cm。每一个粉刷匠到来的时候,只能选择粉刷一面墙 , 而且你必须让他们粉刷一面墙 。 问这m位粉刷匠能否将这n面墙都变成户主期望的颜色 。
思路:把需要改变颜色的墙的信息储存起来 。 然后从后往前遍历粉刷匠 , 其中最后一位粉刷匠携带的颜色必须是需改变的墙的颜色 。对于之前的粉刷匠,如果没有任务,就让它去粉刷之后的粉刷匠会改变的颜色。(例如,最后一个粉刷匠会把第5面墙从红色变成期望的蓝色 , 那么在它之前没有任务的粉刷匠就可以派去随便刷第5面墙)。最后,再判断一下是否所有的墙都是期望的颜色即可。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
int a[maxn],b[maxn],c[maxn],ans[maxn],cnt;vector<int> v[maxn];
int main(){
int t;
cin>>t;
while(t--){
int n,m;cnt = 0;
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
scanf("%d",&b[i]);
for(int i=1;i<=m;i++)
scanf("%d",&c[i]);
for(int i=0;i<=n;i++){
while(v[i].size()!=0)
v[i].pop_back();
}
for(int i=1;i<=n;i++){
if(a[i]!=b[i])
v[b[i]].push_back(i);
}
int able = -1;bool flg = 1;
for(int i=1;i<=n;i++){
if(b[i]==c[m]){
able = i;break;
}
}
for(int i=m;i>=1;i--){
//cout<<c[m]<<endl;
int now = c[i];
if(v[now].size()==0){
if(able==-1){
flg = 0;
break;
}
else{
ans[cnt++] = able;
}
}
else{
int save = v[now].back();
v[now].pop_back();
ans[cnt++] = save;
able = save;
}
}
if(flg==0){
printf("NO\n");
}
else{
for(int i=0;i<=n;i++){
if(v[i].size()!=0)
flg = 0;
}
if(flg==0)
printf("NO\n");
else{
printf("Yes\n");
for(int i=cnt-1;i>=0;i--)
printf("%d ",ans[i]);
printf("\n");
}
}
}
}
D. AB Graph(图论)
(rating:2000)
题意:给一个有向完全图 。图中每一条边都随机赋一个字母a 或 b 。 问题是 : 在图中找到一条路径(可重复边重复点),使得该路径是一个长度为m的回文串。
思路:
用a[i][j] 来存储 i --> j 这条边赋了哪个字母 。
1.当回文串长度为奇数时,显然我们只需要在两点之间反复横跳即可。因为无论是aaaaa这样的,或是ababa这样的 ,在奇数情况下都一定回文。
2.另外可以发现 ,如果存在两点i,j, a[i][j] = a[j][i] , 那么在i,j之间反复横跳取的就是同一个字母,必定回文。
3.当上述情况不满足时,m = 2肯定不成立 ,如题中样例 。
4.那么就剩下一种最难的情况,m是偶数 , 且不满足第2点。
这时要满足回文,就必须找到一个点 y ,使得存在a[x][y] = a[y][z] 。 也就是,存在一个x–>y被赋予的字母 与 y—> z被赋予的字母相同 。 然后让y–>z,x–>y分别作为字符串的首尾 , 中间是 z—>x,x—>z ,z—>x 的反复横跳 。
对于寻找这样的点y,我们不必访问整张图 , 因为题目说了这是个有向完全图,每个点都与别的点相连。 只需要任意取3个点,如果它们的全排列都不满足a[x][y] = a[y][z] , 那么整张图也无此点。
代码:
#include<bits/stdc++.h>
using namespace std;
int n,m;
char a[1005][1005];
void solve(){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i==j) continue;
if(a[i][j]==a[j][i]){
printf("YES\n");
//printf("%d ",i);
for(int k=0;k<=m;k++)
printf("%d ",(k%2)==0?i:j);
printf("\n");
return;
}
}
}
if(m%2==1){
printf("YES\n");
int x = 1,y = 2;
for(int k=0;k<=m;k++){
printf("%d %d ",x,y);k++;
}printf("\n");
return;
}
if(n==2){
printf("NO\n");
return;
}
else{
int b[6][3] = {{1,2,3},{1,3,2},{2,1,3},{2,3,1},{3,1,2},{3,2,1}};
for(int i=0;i<6;i++){
int x = b[i][0],y = b[i][1],z = b[i][2];
if(a[x][y]==a[y][z]){
printf("YES\n");
int len = m/2;
if(m%4==0){
for(int k=0;k<len;k+=2){
printf("%d %d ",y,z);
}
printf("%d ",y);
for(int k=0;k<len;k+=2){
printf("%d %d ",x,y);
}
printf("\n");
}
else{
for(int k=0;k<len;k++){
if(k%2==0)
printf("%d ",z);
else
printf("%d ",y);
}
printf("%d ",y);
for(int k=0;k<len;k++){
if(k%2==0)
printf("%d ",x);
else
printf("%d ",y);
}
printf("\n");
}
return;
}
}
printf("NO\n");
return;
}
}
int main(){
int t;
cin>>t;
while(t--){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i]+1;
}
solve();
}
}
E. Sorting Books(动态规划)
(rating:2500)
题意:书架上有一排书,每本书都有一个颜色ai ,要求最小化操作次数 , 使得相同颜色的书摆在一起。 你所能做的操作是:每次取出一本书,把它放在这排书最右边。(n<=5e5)
思路:这是道非常好的DP题,但是很难,结合好几篇题解想了好久才想通~~
我的想法大致如下:
既然是只能往右边放,那最好就从右往左遍历这排书。设dp[i] 表示对于第i到第n本书,不需要操作的次数,最终结果即n - dp[1]。
假设第i本书是红色,要最小化此时的操作次数:
1)要么对该书操作,把该书往后扔 , 其余的继承之前的最优解 ,也就是dp[i] = dp[i+1] 。
2)要么把之后的所有红书留下,其他非红书的往后扔,此时如果该红色书是最左端的红色书,那么也就是dp[i] = color[红色] + dp[最右端的红色书+1] 。如果不是最左端的红色书,那么dp[i] = color[红色]。(color[红色] 顾名思义,指到目前为止红色书的数量)
两种情况取max。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e5+10;
int a[maxn],color[maxn],dp[maxn];
struct node{
int l;
int r;
}b[maxn];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
if(b[a[i]].l==0) b[a[i]].l = i;
b[a[i]].r = i;
}
for(int i=n;i>=1;i--){
dp[i] = dp[i+1];
color[a[i]]++;
if(i==b[a[i]].l)
dp[i] = max(dp[i],dp[b[a[i]].r+1]+color[a[i]]);
else
dp[i] = max(dp[i],color[a[i]]);
}
cout<<n - dp[1]<<endl;
}