20200912測試總結
阿新 • • 發佈:2020-09-12
考完後的心情:
T1 「MZOI2020」快速班號變換
簡單DP題,沒處理邊界,\(100 \to 70\) 。
令 \(f_{i,j}\) 表示使得 \(a\) 串前 \(i\) 位變換到 \(b\) 串前 \(j\) 位的最小花費,則有轉移:
- 將 \(a_i\) 變成 \(b_j\) ,則 \(f_{i,j}=f_{i-1,j-1}+{\rm{dist}}(a_i,b_j)\) 。
- 刪除 \(a_i\) ,則 \(f_{i,j}=f_{i-1,j}+a_i\) 。
- 插入 \(b_j\) ,則 \(f_{i,j}=f_{i,j-1}+b_j\) 。
\(\text{Code}:\)
memset(f,0x3f,sizeof(f)); f[0][0]=0; for(int i=0;i<=n;++i) for(int j=0;j<=m;++j) { if(i>=1&&j>=1) f[i][j]=min(f[i][j],f[i-1][j-1]+dis(a[i],b[j])); if(j>=1) f[i][j]=min(f[i][j],f[i][j-1]+b[j]); if(i>=1) f[i][j]=min(f[i][j],f[i-1][j]+a[i]); } printf("%d\n",f[n][m]);
T2 「MZOI2020」魔導書
考試的時候想了個錯的貪心,理所應當地爆零了。
假如已經選了一些書疊到了一起,此時上面最多能再疊 \(up\) 本書,對於剩下的書分類討論:
- 若存在一本書,使得它加入後不會改變 \(up\) ,即 \(b\geq up-1\) ,選擇這樣的書中 \(a\) 最大的加入。
- 若不存在上述的書,則選擇一本 \(b\) 儘量大的書,因為這樣能使之後能加入的書儘量多。
按這個思路貪心即可。
\(\text{Code}:\)
#include <cstring> #include <cstdio> #include <algorithm> #define maxn 1000005 #define Rint register int #define INF 0x3f3f3f3f using namespace std; typedef long long lxl; const int mod=910666; template <typename T> inline void read(T &x) { x=0;T f=1;char ch=getchar(); while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} x*=f; } struct Book { int a,b; Book(int a,int b):a(a),b(b){} Book(){} inline bool operator < (const Book &T)const { if(b==T.b) return a<T.a; return b<T.b; } }book[maxn]; int n; struct Segment_Tree { struct node { int l,r,Max; }tree[maxn<<2]; #define ls (p<<1) #define rs (p<<1|1) int a[maxn]; inline int max(const int &x,const int &y) { return a[x]>a[y]?x:y; } inline void maintain(int p) { tree[p].Max=max(tree[ls].Max,tree[rs].Max); } inline void build(int p,int l,int r) { tree[p]=(node){l,r,0}; if(l==r) return void(tree[p].Max=l); int mid=(l+r)>>1; build(ls,l,mid); build(rs,mid+1,r); maintain(p); } inline void update(int p,int ps) { int l=tree[p].l,r=tree[p].r; if(l==r) return void(tree[p].Max=0); int mid=(l+r)>>1; if(ps<=mid) update(ls,ps); else update(rs,ps); maintain(p); } inline int query(int p,int L,int R) { int l=tree[p].l,r=tree[p].r; if(L<=l&&r<=R) return tree[p].Max; int mid=(l+r)>>1,ans=0; if(L<=mid) ans=max(ans,query(ls,L,R)); if(R>mid) ans=max(ans,query(rs,L,R)); return ans; } }sta,stb; int main() { // freopen("B.in","r",stdin); read(n); for(int i=1;i<=n;++i) read(book[i].a); for(int i=1;i<=n;++i) read(book[i].b); sort(book+1,book+n+1); for(int i=1;i<=n;++i) sta.a[i]=book[i].a,stb.a[i]=book[i].b; sta.build(1,1,n);sta.update(1,n); stb.build(1,1,n);stb.update(1,n); int up=book[n].b,ans=book[n].a%mod,cnt=1; while(up>0&&cnt<n) { --up; int p=lower_bound(book+1,book+n+1,Book(-1,up))-book; int now=sta.query(1,p,n); if(now) ans=(ans+book[now].a)%mod; else { now=stb.tree[1].Max; up=book[now].b; ans=(ans+book[now].a)%mod; } ++cnt; sta.update(1,now); stb.update(1,now); } printf("%d\n", ans); return 0; }
T3 「MZOI2020」遺傳因子
考場上想出正解了,然後因為陣列開小,\(100 \to 30\) 。
建一個AC自動機,在fail樹上統計答案即可。
感覺這東西挺套路的。
\(\text{Code}:\)
#include <cstring> #include <cstdio> #include <string> #include <algorithm> #include <queue> #define maxn 10005 #define maxnode 1000005 using namespace std; template <typename T> inline void read(T &x) { x=0;T f=1;char ch=getchar(); while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} x*=f; } struct edge { int u,v,next; }e[maxnode]; int head[maxnode],k; inline void add(int u,int v) { e[k]=(edge){u,v,head[u]}; head[u]=k++; } int n,L[maxn],R[maxn]; char s[maxnode],t[maxnode]; int ch[maxnode][30],tree[maxnode][30],tot,fail[maxnode],book[maxnode]; inline void insert(int id) { int u=0; for(int i=L[id];i<=R[id];++i) { int c=s[i]-'a'+1; if(!ch[u][c]) ch[u][c]=tree[u][c]=++tot; u=ch[u][c]; } book[u]=id; } inline void get_fail() { queue<int> q; memset(fail,-1,sizeof(fail)); for(int i=1;i<=26;++i) if(ch[0][i]) q.push(ch[0][i]),fail[ch[0][i]]=0; while(!q.empty()) { int u=q.front();q.pop(); for(int i=1;i<=26;++i) if(ch[u][i]) { fail[ch[u][i]]=ch[fail[u]][i]; q.push(ch[u][i]); } else ch[u][i]=ch[fail[u]][i]; } for(int i=1;i<=tot;++i) if(~fail[i]) add(fail[i],i); } int f[maxnode],g[maxnode]; inline void dfs(int u) { if(book[u]) { f[u]+=R[book[u]]-L[book[u]]+1; ++g[u]; } for(int i=head[u];~i;i=e[i].next) { int v=e[i].v; f[v]+=f[u]; g[v]+=g[u]; dfs(v); } } int Ans[maxn],Sum; inline void Get_Ans(int u,int sum,int cnt) { if(book[u]) { Ans[book[u]]=(R[book[u]]-L[book[u]]+1)*cnt-sum; Sum+=Ans[book[u]]; } for(int i=1;i<=26;++i) { int v=tree[u][i]; if(!v) continue; Get_Ans(v,sum+f[v],cnt+g[v]); } } int main() { // freopen("C.in","r",stdin); read(n); for(int i=1;i<=n;++i) { scanf(" %s",t+1); L[i]=R[i-1]+1; R[i]=L[i]+strlen(t+1)-1; strcat(s+L[i],t+1); insert(i); } memset(head,-1,sizeof(head)); get_fail(); dfs(0); Get_Ans(0,f[0],g[0]); printf("%d\n",Sum); for(int i=1;i<=n;++i) printf("%d\n",Ans[i]); return 0; }
死亡原因
- DP沒處理邊界。
- 陣列開小。
我退役罷