ASC2 做题记录
A.
预处理出每个状态的转移\(t(u,c)\),然后\(dp(i,j)\)表示长度为\(i\)在DFA上状态为\(j\)DP即可
答案需要高精度
1 #include<bits/stdc++.h> 2 #define MAXL 205 3 using namespace std; 4 const int power = 4; 5 const int base = 10000; 6 struct num 7 { 8 int l; 9 int a[MAXL]; 10 num() { memset(a, 0, sizeof (a));l = 0;} 11 num(const char *s) 12 { 13 memset(a, 0, sizeof (a)); 14 int len = strlen(s); 15 l = (len + power - 1) / power; 16 for (int i = 0, t = 0, j = len - 1, w; i < len; w *= 10, ++i, --j) 17 { 18 if (i % power == 0) {w = 1, ++t;} 19 a[t] += w * (s[j] - '0'); 20 } 21 } 22 friend ostream & operator<<(ostream &o, num &n) 23 { 24 o << n.a[n.l]; 25 for (int i = n.l - 1; i > 0; --i) 26 { 27 if(n.a[i]<10)o<<"000"; 28 else if(n.a[i]<100)o<<"00"; 29 else if(n.a[i]<1000)o<<"0"; 30 o<<n.a[i]; 31 } 32 return o; 33 } 34 }; 35 num operator+(const num &p, const num &q) { 36 num c; 37 c.l = max(p.l, q.l); 38 for (int i = 1; i <= c.l; ++i) { 39 c.a[i] += p.a[i] + q.a[i]; 40 c.a[i + 1] += c.a[i] / base; 41 c.a[i] %= base; 42 } 43 if (c.a[c.l + 1]) ++c.l; 44 return c; 45 } 46 char sig[30]; 47 int m,n,len; 48 int s,L; 49 bool is[1005]; 50 bool vis[1005]; 51 int ph[1005][26],ka[1005][26],t[1005][26]; 52 num dp[65][1005]; 53 int main() 54 { 55 freopen("dfa.in","r",stdin); 56 freopen("dfa.out","w",stdout); 57 scanf("%s",sig); 58 m=strlen(sig); 59 scanf("%d",&n); 60 scanf("%d%d",&s,&L); 61 for(int i=1;i<=L;++i) 62 { 63 int x; 64 scanf("%d",&x); 65 is[x]=1; 66 } 67 for(int i=1;i<=n;++i) 68 for(int j=0;j<m;++j)scanf("%d",&ph[i][j]); 69 for(int i=1;i<=n;++i) 70 for(int j=0;j<m;++j)scanf("%d",&ka[i][j]); 71 for(int i=1;i<=n;++i) 72 for(int j=0;j<m;++j) 73 { 74 memset(vis,0,sizeof(vis)); 75 int u=i; 76 while(ka[u][j]) 77 { 78 if(vis[u])break; 79 vis[u]=1; 80 u=ph[u][j]; 81 } 82 if(vis[u])t[i][j]=0; 83 else t[i][j]=ph[u][j]; 84 } 85 scanf("%d",&len); 86 dp[0][s]=num("1"); 87 for(int i=0;i<len;++i) 88 for(int j=1;j<=n;++j) 89 { 90 for(int k=0;k<26;++k)if(t[j][k]) 91 { 92 dp[i+1][t[j][k]]=dp[i+1][t[j][k]]+dp[i][j]; 93 } 94 } 95 num ans=num("0"); 96 for(int i=1;i<=n;++i) 97 { 98 if(is[i])ans=ans+dp[len][i]; 99 } 100 cout<<ans<<endl; 101 }
B.
多柱汉诺塔
考虑一个n个盘子m个柱子的情况
枚举一个x表示把盘子分成两部分x和n-x,我们的策略是把x个盘子通过m个柱子从s移到pos(某个能放下这x个盘子的位置),然后剩下n-x个盘子从s直接移动到t,然后再把原来的x个盘子从pos移动到t
DP式子为\(dp(i,j)=min(2*dp(i,k)+dp(i-1,j-k))\)
方案按上面策略输出
1 #include<bits/stdc++.h> 2 #define maxn 70 3 using namespace std; 4 typedef unsigned long long ll; 5 int n,m; 6 ll dp[maxn][maxn]; 7 int pre[maxn][maxn]; 8 int stk[maxn][maxn]; 9 int top[maxn]; 10 void print(int s,int t,int mm,int nn) 11 { 12 if(nn==1) 13 { 14 if(top[t]) 15 { 16 printf("move %d from %d to %d atop %d\n",stk[s][top[s]],s,t,stk[t][top[t]]); 17 } 18 else 19 { 20 printf("move %d from %d to %d\n",stk[s][top[s]],s,t); 21 } 22 int x=stk[s][top[s]]; 23 --top[s]; 24 stk[t][++top[t]]=x; 25 return; 26 } 27 int k=pre[mm][nn]; 28 int pos=0; 29 for(int i=1;i<=m;++i)if(i!=s&&i!=t) 30 { 31 if(top[i]&&stk[i][top[i]]<stk[s][top[s]-k+1])continue; 32 pos=i; 33 } 34 print(s,pos,mm,k); 35 print(s,t,mm-1,nn-k); 36 print(pos,t,mm,k); 37 } 38 int main() 39 { 40 freopen("hanoi.in","r",stdin); 41 freopen("hanoi.out","w",stdout); 42 scanf("%d%d",&n,&m); 43 dp[3][1]=1; 44 for(int i=2;i<=64;++i) 45 { 46 dp[3][i]=dp[3][i-1]*2+1; 47 pre[3][i]=i-1; 48 } 49 for(int j=4;j<=m;++j) 50 { 51 dp[j][1]=1; 52 for(int i=2;i<=n;++i) 53 { 54 dp[j][i]=dp[3][64]; 55 for(int k=1;k<i;++k) 56 { 57 if(dp[j][i]>dp[j][k]*2+dp[j-1][i-k]) 58 { 59 dp[j][i]=dp[j][k]*2+dp[j-1][i-k]; 60 pre[j][i]=k; 61 } 62 } 63 } 64 } 65 printf("%d\n",(int)dp[m][n]); 66 for(int i=1;i<=m;++i)top[i]=0; 67 for(int i=1;i<=n;++i)stk[1][++top[1]]=n-i+1; 68 print(1,m,m,n); 69 }
C.
用堆模拟huffman建树
1 #include<bits/stdc++.h> 2 #define maxn 500005 3 using namespace std; 4 typedef long long ll; 5 int n; 6 void read(int &x) 7 { 8 x=0; 9 char ch=getchar(); 10 while(ch<'0'||ch>'9')ch=getchar(); 11 while('0'<=ch&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); 12 } 13 int main() 14 { 15 freopen("huffman.in","r",stdin); 16 freopen("huffman.out","w",stdout); 17 scanf("%d",&n); 18 priority_queue<ll> q; 19 for(int i=1;i<=n;++i) 20 { 21 int x; 22 read(x); 23 q.push(-x); 24 } 25 ll ans=0; 26 while(!q.empty()) 27 { 28 ll u=-q.top();q.pop(); 29 if(q.empty())break; 30 ll v=-q.top();q.pop(); 31 ans+=u+v; 32 q.push(-(u+v)); 33 } 34 printf("%lld\n",ans); 35 }
D.
E.
\(dp(i,j)\)表示第\(i\)个数对应第\(j\)行,然后枚举这行里面选哪个转移,记录方案
1 #include<bits/stdc++.h> 2 #define maxn 1005 3 using namespace std; 4 const int inf = 1000000000; 5 int n,m,s; 6 int x[maxn]; 7 int val[130][130]; 8 int dp[maxn][130],pre[maxn][130],cho[maxn][130]; 9 void print(int i,int j) 10 { 11 if(!i)return; 12 print(i-1,pre[i][j]); 13 printf("%d ",cho[i][j]); 14 } 15 int main() 16 { 17 freopen("quant.in","r",stdin); 18 freopen("quant.out","w",stdout); 19 scanf("%d",&n); 20 for(int i=1;i<=n;++i)scanf("%d",&x[i]); 21 scanf("%d%d",&m,&s); 22 for(int i=0;i<m;++i) 23 for(int j=0;j<s;++j)scanf("%d",&val[i][j]); 24 for(int i=0;i<=n;++i) 25 for(int j=0;j<m;++j)dp[i][j]=inf; 26 dp[0][0]=0; 27 for(int i=1;i<=n;++i) 28 { 29 for(int j=0;j<m;++j) 30 { 31 for(int k=0;k<s;++k) 32 { 33 if(dp[i-1][j]+abs(x[i]-val[j][k])<dp[i][k&(m-1)]) 34 { 35 dp[i][k&(m-1)]=dp[i-1][j]+abs(x[i]-val[j][k]); 36 pre[i][k&(m-1)]=j;cho[i][k&(m-1)]=k; 37 } 38 } 39 } 40 } 41 int ans=inf; 42 for(int j=0;j<m;++j)ans=min(ans,dp[n][j]); 43 printf("%d\n",ans); 44 for(int j=0;j<m;++j)if(ans==dp[n][j]) 45 { 46 print(n,j); 47 break; 48 } 49 }
F.
对于一条树边必然是减,非树边必然是加
那么考虑树边x和非树边y
\(C(x)-\Delta(x) \leq C(y)+\Delta(y)\)
整理得
\(C(x)-C(y) \leq \Delta(x)+\Delta(y)\)
目标是最小\(\Delta(i)\)之和
关系式可以对应KM中顶标和大于等于边权,目标可以对应KM中最小顶标和的性质
那么建立二部图跑KM即可
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn = 405; 5 struct KM{ 6 const ll inf = 1ll << 60; 7 ll G[maxn][maxn], hl[maxn], hr[maxn], dt[maxn]; 8 int fl[maxn], fr[maxn], vl[maxn], vr[maxn], pre[maxn], q[maxn], ql, qr, n; 9 void init(int nl, int nr){ 10 n = max(nl, nr); 11 for(int i = 1; i <= n; ++i) 12 for(int j = 1; j <= n; ++j) G[i][j] = 0; 13 } 14 void add(int u, int v, ll w){ 15 G[u][v] = max(G[u][v], w); 16 } 17 int check(int i){ 18 if(vl[i] = 1, fl[i] != -1) return vr[q[qr++] = fl[i]] = 1; 19 while(i != -1) swap(i, fr[fl[i] = pre[i]]); 20 return 0; 21 } 22 void bfs(int s){ 23 for(int i = 1; i <= n; ++i) vl[i] = vr[i] = 0, dt[i] = inf; 24 for(vr[q[ql = 0] = s] = qr = 1;;){ 25 for(ll d; ql < qr;){ 26 for(int i = 1, j = q[ql++]; i <= n; ++i){ 27 if(!vl[i] && dt[i] >= (d = hl[i] + hr[j] - G[i][j])){ 28 if(pre[i] = j, d) dt[i] = d; 29 else if(!check(i)) return; 30 } 31 } 32 } 33 ll d = inf; 34 for(int i = 1; i <= n; ++i){ 35 if(!vl[i] && d > dt[i]) d = dt[i]; 36 } 37 for(int i = 1; i <= n; ++i){ 38 if(vl[i]) hl[i] += d; 39 else dt[i] -= d; 40 if(vr[i]) hr[i] -= d; 41 } 42 for(int i = 1; i <= n; ++i){ 43 if(!vl[i] && !dt[i] && !check(i)) return; 44 } 45 } 46 } 47 ll solve(){ 48 for(int i = 1; i <= n; ++i) fl[i] = fr[i] = -1, hr[i] = 0; 49 for(int i = 1; i <= n; ++i) 50 { 51 hr[i] = 0; 52 for(int j = 1; j <= n; ++j) hr[i] = max(hr[i], G[j][i]); 53 } 54 for(int i = 1; i <= n; ++i) bfs(i); 55 ll ret = 0; 56 for(int i = 1; i <= n; ++i) if(G[i][fl[i]]) ret += G[i][fl[i]]; else fl[i] = 0; 57 return ret; 58 } 59 }km; 60 int n,m; 61 int C[maxn]; 62 int stk[maxn],top; 63 vector<int> tmp; 64 vector< pair<int,int> > g[maxn]; 65 void dfs(int u,int f,int rt,int t) 66 { 67 if(u==t) 68 { 69 for(int i=1;i<=top;++i)tmp.push_back(stk[i]); 70 } 71 for(auto p:g[u])if(p.first!=f) 72 { 73 stk[++top]=p.second; 74 dfs(p.first,u,rt,t); 75 --top; 76 } 77 } 78 int main() 79 { 80 freopen("roads.in","r",stdin); 81 freopen("roads.out","w",stdout); 82 scanf("%d%d",&n,&m); 83 for(int i=1;i<n;++i) 84 { 85 int u,v,w; 86 scanf("%d%d%d",&u,&v,&w); 87 g[u].push_back(make_pair(v,i)); 88 g[v].push_back(make_pair(u,i)); 89 C[i]=w; 90 } 91 km.init(n-1,m-n+1); 92 for(int i=n;i<=m;++i) 93 { 94 int u,v,w; 95 scanf("%d%d%d",&u,&v,&w); 96 C[i]=w; 97 tmp.clear(); 98 top=0; 99 dfs(u,0,u,v); 100 for(int x:tmp) 101 { 102 km.add(x,i-n+1,C[x]-C[i]); 103 } 104 } 105 km.solve(); 106 for(int i=1;i<n;++i)C[i]-=km.hl[i]; 107 for(int i=n;i<=m;++i)C[i]+=km.hr[i-n+1]; 108 for(int i=1;i<=m;++i)printf("%d\n",C[i]); 109 }
G.
考虑尽量平均分到下取整,然后每次找增量最优的
1 #include<bits/stdc++.h> 2 #define maxn 1005 3 using namespace std; 4 typedef long long ll; 5 int n; 6 ll M,Y,X[maxn],T; 7 ll K[maxn]; 8 int main() 9 { 10 freopen("input.txt","r",stdin); 11 freopen("output.txt","w",stdout); 12 scanf("%d%lld%lld",&n,&M,&Y); 13 T=M; 14 for(int i=1;i<=n;++i) 15 { 16 scanf("%lld",&X[i]); 17 K[i]=X[i]*M/Y; 18 T-=K[i]; 19 } 20 priority_queue< pair<ll,int> > q; 21 for(int i=1;i<=n;++i) 22 { 23 ll c=abs(X[i]*M-K[i]*Y)-abs(X[i]*M-(K[i]+1)*Y); 24 q.push(make_pair(c,i)); 25 } 26 while(T--) 27 { 28 int u=q.top().second;q.pop(); 29 K[u]++; 30 } 31 for(int i=1;i<=n;++i)printf("%lld%c",K[i],(i==n)?'\n':' '); 32 }
H.