2019 年百度之星·程序设计大赛 - 初赛三
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)
=
=
(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
感觉自己写不出来,没细想。