2019 年百度之星·程序设计大赛

旧街凉风 提交于 2020-10-29 07:22:39

 

P.S:关于初赛二,在高铁上打代码真是奇怪的体验!!!

1003,1004的题解很不错,学习了!

 

===========================================

 

一开场把所有的题目看了一遍,这题面风格,感觉凉凉。还好,往下做时,题目不是太坑。

 

1002

floyd转dijkstra+堆优化,感觉是套路题了

  1 #include <cstdio>
  2 #include <cstdlib>
  3 #include <cmath>
  4 #include <cstring>
  5 #include <string>
  6 #include <algorithm>
  7 #include <iostream>
  8 using namespace std;
  9 #define ll long long
 10 #include <queue>
 11 
 12 const double eps=1e-8;
 13 const ll inf=1e9;
 14 const ll mod=998244353;
 15 const int maxn=1e3+10;
 16 
 17 struct node
 18 {
 19     int d;
 20     ll len;
 21     node *to;
 22 }*e[maxn];
 23 
 24 struct rec
 25 {
 26     int d,maxd;
 27     ll dist;
 28     bool operator<(const rec &y) const
 29     {
 30         return dist>y.dist;
 31     }
 32 };
 33 
 34 priority_queue<rec,vector<rec> > st;
 35 
 36 ll dist[maxn];
 37 int maxp[maxn];
 38 
 39 int main()
 40 {
 41     node *p;
 42     int t,n,m,u,v,i,j,be,dd;
 43     ll sum,w;
 44     scanf("%d",&t);
 45     while (t--)
 46     {
 47         scanf("%d%d",&n,&m);
 48         for (i=1;i<=n;i++)
 49             e[i]=0;
 50         while (m--)
 51         {
 52             scanf("%d%d%I64d",&u,&v,&w);
 53             p=new node();
 54             p->d=v;
 55             p->len=w;
 56             p->to=e[u];
 57             e[u]=p;
 58 
 59             p=new node();
 60             p->d=u;
 61             p->len=w;
 62             p->to=e[v];
 63             e[v]=p;
 64         }
 65         sum=0;
 66         for (be=1;be<=n;be++)
 67         {
 68             memset(dist,0x7f,sizeof(dist));
 69             dist[be]=0;
 70             memset(maxp,0,sizeof(maxp));
 71 
 72             while (!st.empty())
 73                 st.pop();
 74 
 75             st.push({be,0,0});
 76             while (!st.empty())
 77             {
 78                 u=st.top().d;
 79                 v=st.top().maxd;
 80                 w=st.top().dist;
 81                 st.pop();
 82                 if (w!=dist[u] || v!=maxp[u])
 83                     continue;
 84                 if (u!=be)
 85                     v=max(v,u);
 86 
 87                 p=e[u];
 88                 while (p)
 89                 {
 90                     dd=p->d;
 91                     if (dist[dd]>w+p->len || (dist[dd]==w+p->len && maxp[dd]>v))
 92                     {
 93                         dist[dd]=w+p->len;
 94                         maxp[dd]=v;
 95                         st.push({dd,v,dist[dd]});
 96                     }
 97                     p=p->to;
 98                 }
 99             }
100 
101             for (i=1;i<=n;i++)
102                 sum+=maxp[i];
103         }
104         printf("%I64d\n",sum%mod);
105     }
106     return 0;
107 }
108 /*
109 2
110 4 2
111 1 2 3
112 2 3 4
113 
114 4 4
115 1 2 1
116 2 3 1
117 3 4 1
118 4 1 1
119 */
120 
121

 

 

但群里有人说,数据不严谨,很多水方法都过了。

 

1003

应该是本人生涯中mobius第一题(赛中),庆祝一下。。。

虽然已经退役了……

 

公式:

mu(x*y)=mu(x)*mu(y)*(gcd(x,y)==1)

跟同学探讨后,以下方法更合理一点

(gcd(i,k)==1)*(gcd(j,k)==1)*mu(i)*mu(j)
=
(gcd(i,k)==1)*(gcd(j,k)==1)*mu(i)*mu(j)*mu(k)*mu(k)
=
mu(ik)*mu(jk)

 

为什么要这样做呢?

想着肯定是只能留一个,即去掉剩下的两个gcd()。

关于gcd(x,y)=1,就是套路了。

 

计算了一下i=1-1e6 mu(i)非0的个数

607926

 

n=1e6时的值,

9185685 (mu!=0)
13970034 (无限制)

 

9185685*10(T) 九千万……

 

原来还是抱了服务器的大腿过的……

 

进一步优化,来自Codeforces讨论(翻译)群群友,

k和d两项合并,

 

时间复杂度

预处理 一千多万

查询 O(nT)

这下没问题了。

 

未优化的代码

比赛时ok,赛后超时了,尴尬……

 1 #include <cstdio>
 2 #include <cstdlib>
 3 #include <cmath>
 4 #include <cstring>
 5 #include <string>
 6 #include <algorithm>
 7 #include <iostream>
 8 using namespace std;
 9 #define ll long long
10 #include <vector>
11 
12 const double eps=1e-8;
13 const ll inf=1e9;
14 const ll mod=1e9+7;
15 const int maxn=1e6+10;
16 
17 int maxv=1e6;
18 
19 bool vis[maxn];
20 int zhi[maxn],cnt_zhi,mu[maxn];
21 vector<int> vec[maxn];
22 
23 int main()
24 {
25     int t,n,m,i,j,k,p,q;
26     ll sum,ans;
27     for (i=2;i<=maxv;i++)
28     {
29         if (!vis[i])
30         {
31             zhi[++cnt_zhi]=i;
32             mu[i]=-1;
33         }
34         for (j=1;j<=cnt_zhi;j++)
35         {
36             k=i*zhi[j];
37             if (k>maxv)
38                 break;
39             vis[k]=1;
40             if (i%zhi[j]==0)
41                 break;
42             else
43                 mu[k]=-mu[i];
44         }
45     }
46     mu[1]=1;
47 
48     for (i=1;i<=maxv;i++)
49     {
50         sum=0;
51         vec[i].push_back(0);
52         for (j=i,k=1;j<=maxv;j+=i,k++)
53         {
54             sum+=mu[j];
55             vec[i].push_back(sum);
56         }
57     }
58 //    exit(0);    ///2.147 s
59 //    printf("%d %d %d",vec[1][5],vec[1][3],vec[2][3]);
60 
61 //    for (i=1;i<=5;i++)
62 //        printf("%d ",mu[i]);
63 //    printf("\n");
64 //    for (i=1;i<=5;i++)
65 //        printf("%d ",vec[1][i]);
66 //    printf("\n");
67 //    for (i=1;i<=5;i++)
68 //        printf("%d ",vec[2][i]);
69 //    printf("\n");
70 
71     scanf("%d",&t);
72     while (t--)
73     {
74         sum=0;
75         scanf("%d%d",&n,&m);
76         p=min(n,m);
77         ///array cal mu[i]!=0
78         for (i=1;i<=p;i++)
79             if (mu[i]!=0)
80             {
81                 ans=0;
82                 q=p/i;
83                 for (j=1;j<=q;j++)
84 //                    ans+=1ll*mu[j]*vec[j][n/(i*j)]*vec[j][m/(i*j)];
85                     ans+=1ll*mu[j]*vec[i*j][n/(i*j)]*vec[i*j][m/(i*j)];
86                 sum+=mu[i]*ans;
87             }
88         printf("%I64d\n",sum);
89     }
90     return 0;
91 }

 

优化后的代码

 1 #include <cstdio>
 2 #include <cstdlib>
 3 #include <cmath>
 4 #include <cstring>
 5 #include <string>
 6 #include <algorithm>
 7 #include <iostream>
 8 using namespace std;
 9 #define ll long long
10 #include <vector>
11 
12 const double eps=1e-8;
13 const ll inf=1e9;
14 const ll mod=1e9+7;
15 const int maxn=1e6+10;
16 
17 int maxv=1e6;
18 
19 bool vis[maxn];
20 int zhi[maxn],cnt_zhi,mu[maxn];
21 ll ans[maxn];
22 vector<int> vec[maxn];
23 
24 int main()
25 {
26     int t,n,m,i,j,k,p;
27     ll sum;
28     for (i=2;i<=maxv;i++)
29     {
30         if (!vis[i])
31         {
32             zhi[++cnt_zhi]=i;
33             mu[i]=-1;
34         }
35         for (j=1;j<=cnt_zhi;j++)
36         {
37             k=i*zhi[j];
38             if (k>maxv)
39                 break;
40             vis[k]=1;
41             if (i%zhi[j]==0)
42                 break;
43             else
44                 mu[k]=-mu[i];
45         }
46     }
47     mu[1]=1;
48 
49     for (i=1;i<=maxv;i++)
50     {
51         sum=0;
52         vec[i].push_back(0);
53         for (j=i,k=1;j<=maxv;j+=i,k++)
54         {
55             sum+=mu[j];
56             vec[i].push_back(sum);
57         }
58     }
59 
60     for (i=1;i<=maxv;i++)
61         if (mu[i]!=0)
62         {
63             k=maxv/i;
64             for (j=1;j<=k;j++)
65                 ans[i*j]+=mu[i]*mu[j];
66         }
67 
68     scanf("%d",&t);
69     while (t--)
70     {
71         sum=0;
72         scanf("%d%d",&n,&m);
73         p=min(n,m);
74         ///array cal mu[i]!=0
75         for (i=1;i<=p;i++)
76             sum+=ans[i]*vec[i][n/i]*vec[i][m/i];
77         printf("%I64d\n",sum);
78     }
79     return 0;
80 }

 

 

1004

可能求导数,卡了一波人,尤其是现在以小学生打比赛比较多的情况下……

感觉是个大水题,遗憾没时间写了。

 

  1 #include <cstdio>
  2 #include <cstdlib>
  3 #include <cmath>
  4 #include <cstring>
  5 #include <string>
  6 #include <algorithm>
  7 #include <iostream>
  8 using namespace std;
  9 #define ll long long
 10 
 11 const double eps=1e-8;
 12 const ll inf=1e9;
 13 const ll mod=998244353;
 14 const int maxn=1<<20|1;
 15 
 16 ll x[maxn];
 17 char op[maxn];
 18 
 19 int main()
 20 {
 21     int m,q,mode,ind,d,dd,i;
 22     ll v,y;
 23     scanf("%d%d",&m,&q);
 24     for (i=1;i<=(1<<(m-1));i++)
 25         x[(1<<(m-1))-1+i]=i;
 26     scanf("%s",op+1);
 27 
 28     ///init
 29     for (i=(1<<(m-1))-1;i>=1;i--)
 30     {
 31         d=i;
 32         if (op[d]=='1')
 33             x[d]=x[d<<1]*x[d<<1|1]%mod;
 34         else
 35             x[d]=(x[d<<1]+x[d<<1|1])%mod;
 36     }
 37 
 38     while (q--)
 39     {
 40         scanf("%d%d",&mode,&ind);
 41         d=ind-1+(1<<(m-1));
 42         if (mode==1)
 43         {
 44             scanf("%lld",&y);
 45             x[d]=y;
 46             while (d!=1)
 47             {
 48                 if (d&1)
 49                     dd=d-1;
 50                 else
 51                     dd=d+1;
 52 
 53                 if (op[d>>1]=='1')
 54                     x[d>>1]=x[d]*x[dd]%mod;
 55                 else
 56                     x[d>>1]=(x[d]+x[dd])%mod;
 57                 d>>=1;
 58             }
 59         }
 60         else
 61         {
 62             v=1;
 63             while (d!=1)
 64             {
 65                 if (d&1)
 66                     dd=d-1;
 67                 else
 68                     dd=d+1;
 69 
 70                 if (op[d>>1]=='1')
 71                     v=v*x[dd]%mod;
 72                 d>>=1;
 73             }
 74             printf("%lld\n",v);
 75         }
 76     }
 77     return 0;
 78 }
 79 /*
 80 3 100
 81 000
 82 2 1
 83 2 2
 84 2 3
 85 2 4
 86 
 87 3 100
 88 001
 89 2 1
 90 2 2
 91 2 3
 92 2 4
 93 
 94 
 95 3 100
 96 110
 97 2 1
 98 2 2
 99 2 3
100 2 4
101 
102 3 100
103 101
104 2 1
105 2 2
106 2 3
107 2 4
108 
109 */

 

 

1005

a[i]>=min(a[i-1],a[i-2])

然后……

 

1006

感觉自己写不出来,没细想。

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!