D. Selection
Time Limit: 1 Sec
Memory Limit: 256 MB
题目连接
http://codeforces.com/gym/100114
Description
When selecting files in an application dialog, Vasya noted that he can get the same selection in different ways. A simple mouse click selects a single file (the existing selection is discarded). A shift-click is used to select a range of files from the file clicked last time to the current file (the existing selection is discarded). Finally, a control-click is used to invert the selection state of a single file. Consider a sequence of actions. First we select file #5 simply by clicking it. Then, shift-clicking file #10 we get the following selection: #5, #6, #7, #8, #9, #10. If after that we control-click files #7 and #3 then we will have files #3, #5, #6, #8, #9, and #10 selected. Shift-clicking file #1 we select files #1, #2, and #3 (last time we clicked file #3, and the previous selection is gone). Vasya is wondering, what the minimum number of clicks will be, to make a certain selection from the list of files. Write a program to determine the optimal way of making the required selection. If there are several minimal solutions, any of them is considered correct. Example. Suppose we are to select files #2, #5, #6, #8, #9 from a list of 10 files. A possible optimal solution will include the following clicks: 5, Shift+9, Ctrl+2, Ctrl+7.
Input
The first line contains an integer n, the number of files in the list. The following line contains n characters defining the required selection. If i-th file is to be selected then there is an asterisk (“*”) in position i, and a dot (“.”) otherwise.
Output
The first line of the output file must contain a single integer k – the minimum number of clicks necessary to make the given selection. The following k lines must define the way to make such a selection. Each line should contain the number of file to be clicked on the corresponding step, and a prefix “Ctrl+” or “Shift+” (without quotation marks) where necessary.
Sample Input
10 .*..**.**.
Sample Output
4 5 Shift+9 Ctrl+2 Ctrl+7
HINT
1 ≤ n ≤ 105 .
题意
有3种操作
1.光标移动到X
2.shift X,直接选择从光标到X的位置
3.选择X,如果X已经被选中,那就取消X的选中状态
问你最少多少步,可以选择所有的*
并且把步骤输出
题解:
注意,只能shift 1次,所以直接扫一遍就好了
跑一遍线段树维护的DP,表示到这儿,所需要的最小代价是多少
代码:
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <cmath> #include <vector> #include <stack> #include <map> #include <set> #include <queue> #include <iomanip> #include <string> #include <ctime> #include <list> #include <bitset> typedef unsigned char byte; #define pb push_back #define input_fast std::ios::sync_with_stdio(false);std::cin.tie(0) #define local freopen("in.txt","r",stdin) #define pi acos(-1) using namespace std; const int maxn = 1e5 + 500; char str[maxn]; int length , sum[maxn], dp[maxn]; vector<int>Q,Q2; struct operation { int x; int type; }; operation nxt[maxn]; struct QueryData { int minv , minpos; QueryData(int minv , int minpos) { this->minv = minv , this->minpos = minpos; } }; typedef int SgTreeDataType; struct treenode { int L , R ; SgTreeDataType minv , minpos; void updata(SgTreeDataType v) { minv = v; } }; treenode tree[maxn * 4]; inline void push_up(int o) { if(tree[o*2].minv > tree[o*2+1].minv) { tree[o].minv = tree[o*2+1].minv; tree[o].minpos = tree[o*2+1].minpos; } else { tree[o].minv = tree[o*2].minv; tree[o].minpos = tree[o*2].minpos; } } inline void build_tree(int L , int R , int o) { tree[o].L = L , tree[o].R = R,tree[o].minv = 1<<29 , tree[o].minpos = 0; if(L == R) tree[o].minpos = L; if (R > L) { int mid = (L+R) >> 1; build_tree(L,mid,o*2); build_tree(mid+1,R,o*2+1); } } inline void updata(int QL,int QR,SgTreeDataType v,int o) { int L = tree[o].L , R = tree[o].R; if (QL <= L && R <= QR) tree[o].updata(v); else { int mid = (L+R)>>1; if (QL <= mid) updata(QL,QR,v,o*2); if (QR > mid) updata(QL,QR,v,o*2+1); push_up(o); } } inline QueryData query(int QL,int QR,int o) { int L = tree[o].L , R = tree[o].R; if (QL <= L && R <= QR) return QueryData(tree[o].minv,tree[o].minpos); else { int mid = (L+R)>>1; if (QL <= mid && QR > mid) { QueryData a = query(QL,QR,2*o); QueryData b = query(QL,QR,2*o+1); if(a.minv < b.minv) return a; else return b; } else if (QL <= mid) return query(QL,QR,2*o); else return query(QL,QR,2*o+1); } } void initiation() { memset( dp , 0 , sizeof(dp)); scanf("%d%s",&length,str+1);sum[0] = 0; for(int i = 1 ; i <= length ; ++ i) { sum[i] = sum[i-1]; if(str[i] == ‘*‘) { Q.push_back(i); } else { sum[i] ++ ; Q2.push_back(i); } } } void solve() { int sz = Q.size(); int ansL = Q[0],ansR = Q[0],ans=sz; build_tree( 0 , sz - 1 , 1 ); for(int i = 0 ; i < sz ; ++ i) updata( i , i , sum[Q[i]] - i , 1); for(int i = 0 ; i < sz - 1; ++ i) { QueryData y = query( i + 1 , sz - 1, 1); int newans = i + 1 + sz + y.minv - sum[Q[i]]; if(newans < ans) { ans = newans; ansL = i; ansR = y.minpos; } } printf("%d\n",ans); if(ansL != ansR) { printf("%d\n",Q[ansL]); printf("Shift+%d\n",Q[ansR]); for(int i = 0 ; i < sz ; ++ i) if(i < ansL || i > ansR) printf("Ctrl+%d\n",Q[i]); for(int i = 0 ; i < Q2.size() ; ++ i) if( Q2[i] < Q[ansR] && Q2[i] > Q[ansL]) printf("Ctrl+%d\n",Q2[i]); } else { printf("%d\n",Q[0]); for(int i = 1 ; i < sz ; ++ i) printf("Ctrl+%d\n",Q[i]); } } int main(int argc,char *argv[]) { freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); initiation(); if(Q.size() == 0) printf("0\n"); else if(Q.size() == 1) printf("1\n%d\n",Q[0]); else if(Q.size() == 2) printf("2\n%d\nCtrl+%d\n",Q[0],Q[1]); else solve(); return 0; }