题意:一个字符串,给定 k 个限制字符对 (ai,bi),要求从原串中删除尽可能少的字符,使得不存在一个相邻的限制字符对。保证 ai=bi,且每个字符最多只出现在一个字符对中。
做法 1
可以设 f[i][c] 表示前 i 位,最后一位为 c 时最少的删除数量,则 ∀j,f[i][j]←f[i−1][j]+1,而特殊地 f[i][s[i]]←(s[i],j) is availablemin{f[i−1][j]}。时间复杂度为 26n。
By rng_58
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| #include <iostream> #include <sstream> #include <string> #include <vector> #include <deque> #include <queue> #include <set> #include <map> #include <algorithm> #include <functional> #include <utility> #include <cmath> #include <cstdlib> #include <ctime> #include <cstdio>
using namespace std;
#define REP(i,n) for((i)=0;(i)<(int)(n);(i)++) #define foreach(c,itr) for(__typeof((c).begin()) itr=(c).begin();itr!=(c).end();itr++)
#define INF (1<<29)
string s,t; bool bad[30][30]; int dp[100010][30];
int main(void){ int K,i,j;
cin >> s; cin >> K; REP(i,K){ cin >> t; bad[t[0]-'a'][t[1]-'a'] = true; bad[t[1]-'a'][t[0]-'a'] = true; }
int N = s.length(); REP(i,N+1) REP(j,27) dp[i][j] = -INF; dp[0][26] = 0;
REP(i,N) REP(j,27){ dp[i+1][j] = max(dp[i+1][j],dp[i][j]); int x = s[i] - 'a'; if(!bad[j][x]) dp[i+1][x] = max(dp[i+1][x],dp[i][j]+1); }
int ans = 0; REP(i,27) ans = max(ans,dp[N][i]); ans = N - ans; cout << ans << endl;
return 0; }
|
做法 2
由于每个字符最多只出现在一个字符对中,所以字符对之间没有交集、互不影响。我们可以对每一个字符对单独处理一遍:假设当前字符对为 (a,b),则对于类似 aaababbaa 的连续子段,要么只能保留 a,要么只能保留 b,每次贪心地删掉较少的即可。时间复杂度 O(kn)。
By peter50216
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| #include<stdio.h> #include<string.h> char in[101000]; int ot[300]; char tmp[10]; int main(){ scanf("%s",in); int k; scanf("%d",&k); while(k--){ scanf("%s",tmp); ot[tmp[0]]=tmp[1]; ot[tmp[1]]=tmp[0]; } int i,j=0; int ans=0; for(i=0;in[i];i=j){ if(ot[in[i]]==0){ j=i+1; continue; } int c1=0,c2=0; while(in[j]&&(in[j]==in[i]||in[j]==ot[in[i]])){ if(in[j]==in[i])c1++; else c2++; j++; } if(c1>c2)c1=c2; ans+=c1; } printf("%d\n",ans); }
|
B. Colliders
题意:你需要维护一个集合,初始为空。有两种操作:
- 尝试加入一个元素。如果集合中没有该元素,且集合中每个元素都与其互质,则成功加入,否则加入失败并输出任意一个不与其互质的元素。
- 尝试删除一个元素。如果集合中本来没有该元素则删除失败,否则删除该元素。
可以维护每个质数是否在集合中出现并维护包含该质数的元素。显然每个质数任意时刻只会被一个元素包含,否则会加入失败。每次加入和删除都质因数分解一次即可。
By rng_58
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
| #include <iostream> #include <sstream> #include <string> #include <vector> #include <deque> #include <queue> #include <set> #include <map> #include <algorithm> #include <functional> #include <utility> #include <cmath> #include <cstdlib> #include <ctime> #include <cstdio>
using namespace std;
#define REP(i,n) for((i)=0;(i)<(int)(n);(i)++) #define foreach(c,itr) for(__typeof((c).begin()) itr=(c).begin();itr!=(c).end();itr++)
int minp[100010]; bool activated[100010]; int a[100010];
int check(int x){ while(x > 1){ int p = minp[x]; while(x%p == 0) x /= p; if(a[p] != 0) return a[p]; } return -1; }
void activate(int x){ int init = x; activated[x] = true; while(x > 1){ int p = minp[x]; while(x%p == 0) x /= p; a[p] = init; } }
void deactivate(int x){ activated[x] = false; while(x > 1){ int p = minp[x]; while(x%p == 0) x /= p; a[p] = 0; } }
void plus_query(int x){ if(activated[x]){ printf("Already on\n"); return; }
int ans = check(x); if(ans == -1){ printf("Success\n"); activate(x); } else { printf("Conflict with %d\n",ans); } }
void minus_query(int x){ if(!activated[x]){ printf("Already off\n"); return; }
printf("Success\n"); deactivate(x); }
char buf[10];
int main(void){ int N,Q,i,j,x;
scanf("%d%d",&N,&Q);
for(i=2;i<=N;i++) minp[i] = i; for(i=2;i<=N;i++) if(minp[i] == i) for(j=2*i;j<=N;j+=i) minp[j] = min(minp[j],i);
REP(i,Q){ scanf("%s",buf); scanf("%d",&x); if(buf[0] == '+') plus_query(x); else minus_query(x); }
return 0; }
|
C.