Noip模拟32(再度翻车) 2021.8.7
T1 Smooth
很水的一道题。。。可是最傻 的是考场上居然没有想到用优先队列优化。。。
上来开题看到这个,最一开始想,这题能用模拟短除法,再一想太慢了,就想着优化
偏偏想到线性筛然后试别的素数是不是他的因数,比较离谱当时为什么会觉得这样快。。。
然后还在试图精准卡时限,感觉自己像时间管理带师(??),总之就非常逗 。
后来发现这种做法不仅没有正确性(因为素数可能筛不完),而且还慢。。。
就放弃了直接打了一手短除,拿到除了暴零以外的全场最低$20$,长个教训吧。。。。。
据说正解跟蚯蚓很像,但是没做过不慌,毕竟场上想到正解思路,但是没有想到如何快速找最小值
考后一听别人讨论优先队列就知道该怎么打了,然后不到半个小时就$A$了
奈何考场上像一个傻 。。。。。
总共就最多$15$个质数,对于每一个质数都开一个队列,其实不用优先队列
可以发现每个合理的$B-Smooth$数都是由$prime_b$之前的质数随便组合相乘得到的
那么每次从所有的队列首找到最小的,为了不重复让他乘上比他大的还小于$prime_b$的质数
依次放入那种质数的队列中,然后到$k$位置直接输出就行。
1 #include<bits/stdc++.h> 2 #define int long long 3 using namespace std; 4 int b,k,p[20]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67},cnt; 5 queue<int> Q[20]; 6 namespace WSN{ 7 inline short main(){ 8 scanf("%lld%lld",&b,&k); 9 for(int i=1;i<=b;i++) Q[i].push(p[i]);cnt=1; 10 while(1){ 11 int minn=1e18,pos=0; 12 for(int i=1;i<=b;i++) if(minn>Q[i].front()) 13 minn=Q[i].front(),pos=i; 14 Q[pos].pop();++cnt; if(cnt==k){printf("%lld\n",minn);break;} 15 for(int i=pos;i<=b;i++) 16 Q[i].push(minn*p[i]); 17 } 18 return 0; 19 } 20 } 21 signed main(){return WSN::main();}
T2 Six
首先要理解:组成数列中唯一的限制都只跟这个数的质因数有关,跟其他的约数无关。
原因:任意一个数都可以表示为质因数相乘的形式,那么他的约数也都跟质因数不互质,
所以关于题目里面加入一个约数,保证其与前面的数至多有一个不互质,
就是说质因数在这个数列中不可以出现两次以上(单独出现也好,还是在一个约数的质因数里面也好,都不可以出现两次以上)。
解释完后,题意就被转化了,看似巨大的测试数据也就缩小到很小了,六位的状压。
剩下就是枚举集合,进行记忆化搜索就行了,直接口胡说不清,代码里面有注释。
1 #include<bits/stdc++.h> 2 #define int long long 3 #define pii pair<int ,int> 4 #define mp make_pair 5 #define num first 6 #define cnt second 7 using namespace std; 8 const int NN=1000005,mod=1e9+7; 9 int N,rp,sum[1<<7];//sum数组记录的是在状态sta(表示选择了哪些质数组成N)下的所有成立的N有几种 10 pii p[7];//记录质因数及其指数,其实只记录指数即可 11 unordered_map<int ,int > dp;//记录每一种状态对应的方案数 12 inline int cal(int S,int T){//就是在求dfs中的T集合,注意这里的T集合与dfs中的不同,S,T单是表示选择的质数 13 int ans=0; 14 for(int i=0;i<rp;i++) for(int j=0;j<=i;j++) 15 if( ( (S>>i&1) && (T>>j&1) ) || ( (T>>i&1) && (S>>j&1) ) ) ans|=1<<(i*(i+1)/2+j); 16 //如果S,T中包含两个元素i,j,就将其打包装入T集合,那个给ans赋值柿子那么奇妙是因为他的实质就是hash,只是为了去重的手段 17 return ans; 18 } 19 inline bool check(int S,int T){ 20 for(int i=0;i<rp;i++) for(int j=0;j<=i;j++) 21 if( ( (S>>i&1) && (S>>j&1) ) && (T>>(i*(i+1)/2+j)&1)) return 0;//如果S中有i,j这两个元素,且T中有这两个互质对 22 return 1; 23 } 24 inline int dfs(int S,int T){//S集合表示选择了哪几种质数,T集合表示组成的质数对,其中的位数没有直接含义,具体见尻函数 25 int now=(S<<30)+T; 26 if(dp.find(now)!=dp.end()) return dp[now]; 27 dp[now]=1; 28 for(int i=1;i<(1<<rp);i++) if(check(i,T)) 29 (dp[now]+=sum[i]*dfs(S|i,T|cal(S,i))%mod)%=mod;//枚举可能的集合,进行状态转移 30 return dp[now]; 31 } 32 namespace WSN{ 33 inline short main(){ 34 scanf("%lld",&N); 35 for(int i=2;i<=sqrt(N);i++){ 36 if(N%i!=0) continue; 37 p[++rp].num=i; 38 while(N%i==0) ++p[rp].cnt,N/=i; 39 }if(N!=1) p[++rp]=mp(N,1);//对N进行质因数拆分 40 /* for(int i=1;i<=rp;i++) 41 cout<<p[i].num<<" "<<p[i].cnt<<endl;*/ 42 for(int i=1;i<(1<<rp);i++){//预处理sum数组 43 sum[i]=1; 44 for(int j=0;j<rp;j++) 45 if(i>>j&1) (sum[i]*=p[j+1].cnt)%=mod;//注意j+1,容易忘 46 } 47 printf("%lld\n",dfs(0,0)-1); 48 return 0; 49 } 50 } 51 signed main(){return WSN::main();}
T3 Walker
考场上一看弧度和三角函数的转化就傻了,根本没学过。。
看一眼数据范围乐开花,有$30$分压根不用思考。。。。。
正解果然是高斯消元,不过使用方法极为奇妙。。。
真就正解随机化
复杂度$O(4^3rp)$,比较喜人。。。。
随机出来两个人,将其$x,y$作为常数列出$4*5$的行列式消元,
只要有唯一解就用其进行回代判断$\frac{1}{2}$的条件。
计算五十组,全部找不到正确的解的概率为$(\frac{3}{4})^50$
最后,有一个东西叫——
精度
很烦人,一旦不对就是一下午望穿秋水,啥也调不出来。。。。。。
1 #include<bits/stdc++.h> 2 #define wsn double 3 using namespace std; 4 const int NN=1e5+5; 5 int n; 6 wsn g[6][6]; 7 struct node{wsn x,y;}p1[NN],p2[NN]; 8 inline int Gauss(int n){ 9 int cnt=1; 10 for(int i=1;i<=n;i++){ 11 int r=cnt; 12 for(int j=cnt;j<=n;j++) if(fabs(g[j][i])>fabs(g[r][i])) r=j; 13 if(fabs(g[r][i])<1e-5) return 0; 14 for(int j=i;j<=n+1;j++) swap(g[r][j],g[cnt][j]); 15 for(int j=n+1;j>=i;j--) g[cnt][j]/=g[cnt][i]; 16 for(int j=cnt+1;j<=n;j++) if(fabs(g[j][i])>1e-5) 17 for(int k=n+1;k>=i;k--) g[j][k]-=g[cnt][k]*g[j][i]; 18 cnt++; 19 } 20 for(int i=n;i>=1;i--) for(int j=i+1;j<=n;j++) 21 g[i][n+1]-=g[i][j]*g[j][n+1]; 22 return 1; 23 } 24 inline bool check(int ren){ 25 int tmp=0; 26 //g[1][5] cos*scale 27 //g[2][5] sin*scale 28 //g[3][5] dx 29 //g[4][5] dy 30 if(fabs(p1[ren].x*g[1][5]-p1[ren].y*g[2][5]+g[3][5]-p2[ren].x)<1e-5) ++tmp; 31 if(fabs(p1[ren].x*g[2][5]+p1[ren].y*g[1][5]+g[4][5]-p2[ren].y)<1e-5) ++tmp; 32 return tmp==2; 33 } 34 namespace WSN{ 35 inline short main(){srand(time(0)); 36 scanf("%d",&n); 37 for(int i=1;i<=n;i++) 38 scanf("%lf%lf%lf%lf",&p1[i].x,&p1[i].y,&p2[i].x,&p2[i].y); 39 for(int w=1;w<=100;w++){ 40 int ren1=rand()%n+1,ren2=rand()%n+1; 41 while(ren1==ren2){ren1=rand()%n+1;ren2=rand()%n+1;} 42 g[1][1]=p1[ren1].x,g[1][2]=-p1[ren1].y,g[1][3]=1,g[1][4]=0,g[1][5]=p2[ren1].x; 43 g[2][1]=p1[ren1].y,g[2][2]= p1[ren1].x,g[2][3]=0,g[2][4]=1,g[2][5]=p2[ren1].y; 44 g[3][1]=p1[ren2].x,g[3][2]=-p1[ren2].y,g[3][3]=1,g[3][4]=0,g[3][5]=p2[ren2].x; 45 g[4][1]=p1[ren2].y,g[4][2]= p1[ren2].x,g[4][3]=0,g[4][4]=1,g[4][5]=p2[ren2].y; 46 if(!Gauss(4)) continue; 47 int jishuqi=0; 48 for(int i=1;i<=n;i++) if(check(i)) ++jishuqi; 49 if(jishuqi>=(n+1)/2) break; 50 } 51 wsn scale=sqrt(g[1][5]*g[1][5]*1.0+g[2][5]*g[2][5]*1.0); 52 wsn arc=acos(g[1][5]/scale); 53 if(g[2][5]<0) arc=-arc; 54 printf("%.10lf\n%.10lf\n%.10lf %.10lf\n",arc,scale,g[3][5],g[4][5]); 55 return 0; 56 } 57 } 58 signed main(){return WSN::main();}

浙公网安备 33010602011771号