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 }
View Code

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 }
View Code

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 }
View Code

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 }
View Code

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 }
View Code

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 }
View Code

H.

 

posted @ 2020-12-13 13:00  幽蝶  阅读(240)  评论(0编辑  收藏  举报