2017 多校联合训练 4 题解

Problem 1004

直接用数组模拟

为了避免memset

可以一遍正着统计,一遍倒着统计

注意统计的时候不能出现乘除法

不然会T

然后记录一个cnt

cnt大于2e8就跳出

同时有效数字的位数够了也跳出

当然所有的数都不同以及只有2个数相同要特殊处理

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<queue>
using namespace std;
const double eps=1e-5;
int _,n,a[60010];
int p[60010],q[60010];
int main()
{
    scanf("%d",&_);
    while (_--)
    {
        scanf("%d",&n);
        int i,j;
        for (i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            p[a[i]]=0,q[a[i]]=0;
        }
        int mx=0,cnt=0;
        for (i=1;i<=n;i++)
        {
            if (q[a[i]])
                mx=max(mx,i-q[a[i]]);
            else cnt++;
            q[a[i]]=i;
        }
        if (cnt==1)
        {
            printf("%.9f
",1.0/n);
            continue;
        }
        else if (cnt==2)
        {
            if (2*(mx-1)<n) printf("%.9f
",2.0/n);
            else printf("%.9f
",1.0/(mx-1));
            continue;
        }
        p[a[1]]++;
        int fz=1;
        double ans=cnt*1.0/n;
        cnt=0;
        for (i=2;i<=n;i++)
        {
            int nfz;
            if (i&1)
            {
                if (!p[a[n-i+1]])
                    fz++;
                p[a[n-i+1]]++;
                int pre=n;
                nfz=fz;
                for (j=n-i;j>=1;j--)
                {
                    p[a[pre]]--;
                    if (!p[a[pre]]) fz--;
                    if (!p[a[j]]) fz++;
                    p[a[j]]++;
                    if (fz<nfz) nfz=fz;
                    pre--;
                    cnt++;
                    if (cnt>2e8) break;
                }
            }
            else
            {
                if (!p[a[i]]) fz++;
                p[a[i]]++;
                int pre=1;
                nfz=fz;
                for (j=i+1;j<=n;j++)
                {
                    p[a[pre]]--;
                    if (!p[a[pre]]) fz--;
                    if (!p[a[j]]) fz++;
                    p[a[j]]++;
                    if (fz<nfz) nfz=fz;
                    pre++;
                    cnt++;
                    if (cnt>2e8) break;
                }
            }
            double as=nfz*1.0/i;
            //cout<<nfz<<" "<<i<<endl;
            if (as<ans) ans=as;
            if (ans<eps) break;
            if (cnt>2e8) break;
        }
        printf("%.9f
",ans);
    }
    return 0;
}
View Code

Problem 1005

w=min(d1,2,d2,3)w=min(d1,2​​,d2,3​​)

因为一条边可以往返跑2ci

所以如果存在距离为d的方案

那么一定存在距离为d+2w的方案

设f[i][j]为从起点出发到i,距离模2w为j时的最短路

根据f[2][j]解不等式即可

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstdlib>
 5 #include<algorithm>
 6 #include<cstring>
 7 #include<string>
 8 #include<vector>
 9 #include<map>
10 #include<set>
11 #include<queue>
12 #include<functional>
13 using namespace std;
14 typedef long long ll;
15 typedef pair<ll,int> P;
16 const ll inf=1ll<<62;
17 int _,g[4],st;
18 ll f[4][60001],k;
19 priority_queue<P,vector<P>,greater<P> >q;
20 void upd(int x,int y,ll z)
21 {
22     if (z<f[x][y])
23     {
24         f[x][y]=z;
25         q.push({z,y<<2|x});
26     }
27 }
28 int main()
29 {
30     scanf("%d",&_);
31     while (_--)
32     {
33         scanf("%lld%d%d%d%d",&k,&g[0],&g[1],&g[2],&g[3]);
34         st=min(g[0],g[1])*2;
35         int i,j;
36         for (i=0;i<4;i++)
37             for (j=0;j<st;j++) f[i][j]=inf;
38         upd(1,0,0);
39         while (!q.empty())
40         {
41             P t=q.top();
42             q.pop();
43             int x=t.second%4;
44             int y=t.second/4;
45             if (f[x][y]<t.first) continue;
46             upd((x+1)%4,(y+g[x])%st,t.first+g[x]);
47             upd((x+3)%4,(y+g[(x+3)%4])%st,t.first+g[(x+3)%4]);
48         }
49         ll ans=inf;
50         for (i=0;i<st;i++)
51             if (f[1][i]<k)
52             {
53                 ll sum=f[1][i]+(k-f[1][i])/st*st;
54                 while (sum<k) sum+=st;
55                 ans=min(ans,sum);
56             }
57             else
58                 ans=min(ans,f[1][i]);
59         printf("%lld
",ans);
60     }
61     return 0;
62 }
View Code

Problem 1007

度数为1的点匹配方案是唯一的

先拓扑排序去掉所有度数为1的点

剩下的图的每个连痛快是个环

间隔取环上的点

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<cstdlib>
  5 #include<algorithm>
  6 #include<cstring>
  7 #include<string>
  8 #include<vector>
  9 #include<map>
 10 #include<set>
 11 #include<queue>
 12 using namespace std;
 13 typedef long long ll;
 14 const ll mod=998244353;
 15 int _,n,du[600010],p[600100];
 16 bool vis[600010];
 17 vector<pair<int,int>> a[600010];
 18 int get(int x,int y)
 19 {
 20     for (auto u:a[x])
 21         if (u.first==y) return u.second;
 22 }
 23 int main()
 24 {
 25     scanf("%d",&_);
 26     while (_--)
 27     {
 28         scanf("%d",&n);
 29         int i,j;
 30         for (i=1;i<=2*n;i++)
 31             a[i].clear();
 32         memset(du,0,sizeof(du));
 33         memset(vis,false,sizeof(vis));
 34         for (i=1;i<=n;i++)
 35             for (j=0;j<2;j++)
 36             {
 37                 int x,y;
 38                 scanf("%d%d",&x,&y);
 39                 a[i].push_back({x+n,y});
 40                 a[x+n].push_back({i,y});
 41                 du[i]++;
 42                 du[x+n]++;
 43             }
 44         n<<=1;
 45         queue<int> q;
 46         for (i=1;i<=n;i++)
 47             if (du[i]==1)
 48                 q.push(i);
 49         ll ans=1;
 50         while (!q.empty())
 51         {
 52             int x=q.front();
 53             q.pop();
 54             int y;
 55             for (auto u:a[x])
 56                 if (!vis[u.first])
 57                 {
 58                     y=u.first;    
 59                     ans=1ll*ans*u.second%mod;
 60                     break;
 61                 }
 62             vis[x]=vis[y]=true;
 63             for (auto u:a[y])
 64                 if (!vis[u.first])
 65                 {
 66                     du[u.first]--;
 67                     if (du[u.first]==1)
 68                         q.push(u.first);
 69                 }
 70         }
 71         for (i=1;i<=n;i++)
 72             if (!vis[i])
 73             {
 74                 vis[i]=true;
 75                 int cnt=1;
 76                 p[cnt]=i;
 77                 int cm=i;
 78                 while (true)
 79                 {
 80                     bool fg=true;
 81                     for (auto u:a[cm])
 82                         if (!vis[u.first])
 83                         {
 84                             fg=false;
 85                             cm=u.first;
 86                             break;
 87                         }
 88                     if (fg) break;
 89                     //cout<<cm<<" ";
 90                     vis[cm]=true;
 91                     p[++cnt]=cm;
 92                 }
 93                 //cout<<endl;
 94                 p[cnt+1]=p[1];
 95                 ll x=1,y=1;
 96                 for (j=1;j<=cnt;j+=2) x=1ll*x*get(p[j],p[j+1])%mod;
 97                 for (j=2;j<=cnt;j+=2) y=1ll*y*get(p[j],p[j+1])%mod;
 98                 ans=1ll*ans*(x+y)%mod;    
 99             }
100         printf("%lld
",ans);
101     }
102     return 0;
103 }
View Code

Problem 1011

按照题意模拟即可

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<cstdlib>
  5 #include<algorithm>
  6 #include<cstring>
  7 #include<string>
  8 #include<vector>
  9 #include<map>
 10 #include<set>
 11 #include<queue>
 12 using namespace std;
 13 const char s[10][8][5]=
 14 {{".XX.",
 15   "X..X",
 16   "X..X",
 17   "....",
 18   "X..X",
 19   "X..X",
 20   ".XX."},
 21  
 22  {"....",
 23   "...X",
 24   "...X",
 25   "....",
 26   "...X",
 27   "...X",
 28   "...."},
 29  
 30  {".XX.",
 31   "...X",
 32   "...X",
 33   ".XX.",
 34   "X...",
 35   "X...",
 36   ".XX.",},
 37  
 38  {".XX.",
 39   "...X",
 40   "...X",
 41   ".XX.",
 42   "...X",
 43   "...X",
 44   ".XX." },
 45  
 46  {"....",
 47   "X..X",
 48   "X..X",
 49   ".XX.",
 50   "...X",
 51   "...X",
 52   "...."},
 53  
 54  {".XX.",
 55   "X...",
 56   "X...",
 57   ".XX.",
 58   "...X",
 59   "...X",
 60   ".XX.",},
 61   
 62  {".XX.",
 63   "X...",
 64   "X...",
 65   ".XX.",
 66   "X..X",
 67   "X..X",
 68   ".XX.",},
 69  
 70  {".XX.",
 71   "...X",
 72   "...X",
 73   "....",
 74   "...X",
 75   "...X",
 76   "...."},
 77   
 78  { ".XX.",
 79    "X..X",
 80    "X..X",
 81    ".XX.",
 82    "X..X",
 83    "X..X",
 84    ".XX.",},
 85  
 86  { ".XX.",
 87    "X..X",
 88    "X..X",
 89    ".XX.",
 90    "...X",
 91    "...X",
 92    ".XX.",}
 93   };
 94 char c[8][22];
 95 void check(int pos)
 96 {
 97     int num,i,j;
 98     for (num=0;num<10;num++)
 99     {
100         bool ok=true;
101         for (i=0;i<7;i++)
102         {
103             for (j=pos;j<=pos+3;j++)
104                 if (c[i][j]!=s[num][i][j-pos])
105                 {
106                     ok=false;
107                     break;
108                 }
109             if (!ok) break;
110         }
111         if (ok)
112         {
113             printf("%d",num);
114             return;
115         }
116     }
117 }
118 int main()
119 {
120     int _;
121     scanf("%d",&_);
122     while (_--)
123     {
124         int i,j;
125         for (i=0;i<7;i++)
126             scanf("%s",c[i]);
127         check(0);
128         check(5);
129         printf(":");
130         check(12);
131         check(17);
132         printf("
");
133     }
134     return 0;
135 }
View Code

Problem 1012

f[i][j][k]表示只考虑a,b两个数组,上升下降状态是k的方案数

直接暴力枚举会T

这时可以建立辅助数组g和h

g[i][y][z]表示从f[x][y][z]开始,要更新的是i的方案数

h[i][j][z]表示从f[x][y][z]开始,已经经过g,要更新的是j的方案数

这样每次就只有一个变量在动

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstdlib>
 5 #include<algorithm>
 6 #include<cstring>
 7 #include<string>
 8 #include<vector>
 9 #include<map>
10 #include<set>
11 #include<queue>
12 using namespace std;
13 const int mod=998244353;
14 int _,n,m,a[2010],b[2010];
15 int g[2010][2010][2],h[2010][2010][2];
16 int main()
17 {
18     scanf("%d",&_);
19     while (_--)
20     {
21         scanf("%d%d",&n,&m);
22         int i,j,k;
23         for (i=1;i<=n;i++) scanf("%d",&a[i]);
24         for (i=1;i<=m;i++) scanf("%d",&b[i]);
25         memset(g,0,sizeof(g));
26         memset(h,0,sizeof(h));
27         int ans=0;
28         for (i=1;i<=n;i++)
29             for (j=1;j<=m;j++)
30                 for (k=0;k<2;k++)
31                 {
32                     if (a[i]==b[j])
33                     {
34                         int t=h[i][j][1-k];
35                         if (!k) t=(t+1)%mod;
36                         if (t)
37                         {
38                             ans=(ans+t)%mod;
39                             g[i+1][j][k]=(g[i+1][j][k]+t)%mod;
40                         }
41                     }
42                     if (g[i][j][k])
43                     {
44                         g[i+1][j][k]=(g[i+1][j][k]+g[i][j][k])%mod;
45                         if (!k)
46                         {
47                             if (a[i]>b[j])
48                                 h[i][j+1][k]=(h[i][j+1][k]+g[i][j][k])%mod;
49                         }
50                         else
51                         {
52                             if (a[i]<b[j])
53                                 h[i][j+1][k]=(h[i][j+1][k]+g[i][j][k])%mod;
54 
55                         }
56                     }
57                     if (h[i][j][k]) h[i][j+1][k]=(h[i][j+1][k]+h[i][j][k])%mod;
58                 }
59         printf("%d
",ans);
60     }
61     return 0;
62 }
View Code
原文地址:https://www.cnblogs.com/cxhscst2/p/7441885.html