T1
子序列自动机,对于每一个字符开一个节点,当前位置的后面下一个0在哪里,这个节点的0指针就指向哪里,1即同理。
建两个自动机,然后dp,\(dp[i][j]\)表示走到\(A\)自动机第i个位置,\(B\)自动机第\(j\)个位置的最短长度,如果把无效节点称为\(len+1\)节点,求的答案即是\(dp[n+1][m+1]\)。
转移时从左往右,如果有当前在\(A,B\)两个自动机上的位置\(x,y\),取0指针往后跳到的点i_A和i_B,用自己的\(dp[x][y]+1\)去更新后面的\(dp[i_A][i_b]\),1同理。
T2
只考虑元素最小的一些1,它一定放到最两边,所以直接贪心地去放,考虑左边一串的1放在左边,右边的1放在右边枚举断点在哪里最好;再在剩下的数中考虑2;以此类推。
计算代价:求剩余卡牌中在这张前面和目标位置之间有多少张就有多少代价,计算即可。由于相同的卡牌之间的顺序并没有关系,要先把相同卡牌权值删掉之后再进行统计。
代码
#include <cstdlib> #include <iostream> #include <cstring> #include <algorithm> #include <cctype> #include <cstdio> #include <vector> using namespace std; #define FILENAME "card" #if (defined D) #define DEBUG(...) printf(__VA_ARGS__) #define PRINTARR(formatstr, arr, beginoff, size) \ do{printf(#arr ":"); \ for (int __i = beginoff; __i <= beginoff + size - 1; __i++) \ printf("\t%d", __i); \ printf("\n"); \ for (int __i = beginoff; __i <= beginoff + size - 1; __i++) \ printf("\t" formatstr, arr[__i]); \ printf("\n"); }while(false) #define PASS printf("Passing function \"%s\" on line %d\n", __func__, __LINE__) #define ASSERT(expr) do{\ if(!(expr)){\ printf("Debug Assertation Failed on line %d, in function %s:\n Expression: %s\n",__LINE__,__func__,#expr);\ abort();\ }\ }while(false) #else #define DEBUG(...) #define PRINTARR(a, b, c, d) #define PASS #define ASSERT(expr) #endif const int bufferreadsize = 30 * 1024 * 1024; const int bufferwritesize = 1024; char buffer[bufferreadsize], *buffertop = buffer; #define GETCHAR *(buffertop++) #define UNGETCHAR(c) (--buffertop) template<typename IntType> inline IntType read() { IntType val = 0; int c; bool invflag = false; while (!isdigit(c = GETCHAR)) if (c == '-') invflag = true; do { val = (val << 1) + (val << 3) + c - '0'; } while (isdigit(c = GETCHAR)); UNGETCHAR(c); if (invflag) return -val; else return val; } template<> inline string read<string>() { string str; str.clear(); int c; while (iscntrl(c = GETCHAR) || c == ' ' || c == '\t'); do { str.push_back(c); } while (!(iscntrl(c = GETCHAR) || c == ' ' || c == '\t')); UNGETCHAR(c); return str; } template<typename IntType> inline void read(IntType& x) { x = read<IntType>(); } char bufferwrite[bufferwritesize], *writetop = bufferwrite; #define PUTCHAR(c) (*(writetop++) = (c)) inline void putstr(char* str) { while ((*str) != '\0') { PUTCHAR(*str); str++; } } template<typename IntType> inline void println(IntType val) { if (val == 0) PUTCHAR('0'); if (val < 0) { PUTCHAR('-'); val = -val; } char buf[16], *buftop = buf + 15; while (val > 0) { *buftop = (val % 10 + '0'); buftop--; val /= 10; } for (buftop++; buftop <= buf + 15; buftop++) PUTCHAR(*buftop); PUTCHAR('\n'); } /******************** End of quickread template ********************/ const int MaxN=100000+10; int n,a[MaxN]; vector<int> pos[MaxN]; struct node{ int left,right; node* lson,*rson; int sum; }; node* root; node mem[2*MaxN],*memtop=mem; #define ALLOCATE (++memtop) void build(int left=1,int right=n,node*& p=root){ p=ALLOCATE; p->left=left; p->right=right; if(left==right) p->sum=1; else{ int mid=(left+right)/2; build(left,mid,p->lson); build(mid+1,right,p->rson); p->sum=p->lson->sum+p->rson->sum; } } void setval(int pos,int val,node* p=root){ if(p->left==pos&&p->right==pos){ p->sum=val; return; } if(p->lson->right>=pos) setval(pos,val,p->lson); else setval(pos,val,p->rson); p->sum=p->lson->sum+p->rson->sum; } int query(int left,int right,node* p=root){ if(right<left) return 0; if(p->left==left&&p->right==right) return p->sum; if(p->lson->right>=right) return query(left,right,p->lson); else if(p->rson->left<=left) return query(left,right,p->rson); else return (query(left,p->lson->right,p->lson)+ query(p->rson->left,right,p->rson)); } int main(int argc, char* argv[]) { #if (defined LOCAL) || (defined ONLINE_JUDGE) FILE* in = stdin, *out = stdout; #else FILE* in = fopen(FILENAME ".in", "rb"); FILE* out = fopen(FILENAME ".out", "wb"); #endif fread(buffer, 1, bufferreadsize, in); fclose(in); read(n); for(int i=1;i<=n;i++){ read(a[i]); pos[a[i]].push_back(i); } build(); int ans=0; for(int i=1;i<=100000;i++){ if(pos[i].empty()) continue; DEBUG("a=%d has contents\n",i); for(int j=0;j<pos[i].size();j++) setval(pos[i][j],0); int k=query(1,n); for(int j=0;j<pos[i].size();j++){ DEBUG(" a[%d]=%d",pos[i][j],i); int l=query(1,pos[i][j]-1),r=k-l; DEBUG(", l=%d, r=%d\n",l,r); ans+=min(l,r); } } println(ans); fwrite(bufferwrite, 1, writetop - bufferwrite, out); fclose(out); return 0; }
T3
考虑推出一个有关于答案的式子:相邻两个节点的距离累加起来(包括第一个和最后一个)然后除以二……于是加减点变得很简单……
所以我们只要对于每一种颜色维护一个按照dfs序排序的set即可