[考试反思]0928csp-s模拟测试54:转瞬

咕了好久,也没什么想说的。

下一场就又爆炸了。。。

T3特判打丢一句话丢了14分,剩下其实都还好。

T1:x

给我的第一感觉是建图找联通块,但既然只要找联通块为什么不直接并查集呢?

对于每一个数字合并它的所有因子,求出现过的因子形成几个联通块,特殊处理1。

二营长比我快了整整5分钟做出来的。

 1 #include<cstdio>
 2 #include<vector>
 3 using namespace std;
 4 #define mod 1000000007
 5 #define int long long 
 6 vector<int>v[1000005];
 7 int x[100005],al[1000005],f[1000005],prime[1000005],cnt_prime;bool not_prime[1000005];
 8 int pow(int b,int t,int a=1){for(;t;t>>=1,b=b*b%mod)if(t&1)a=a*b%mod;return a;}
 9 int find(int k){return f[k]==k?k:f[k]=find(f[k]);}
10 main(){
11     int t;scanf("%lld",&t);
12     for(int i=2;i<=1000000;++i)if(!not_prime[i]){
13         prime[++cnt_prime]=i;
14         for(int j=i;j<=1000000;j+=i)v[j].push_back(i),not_prime[j]=1;
15     }
16     while(t--){
17         int n,cnt1=0;scanf("%lld",&n);
18         for(int i=1;i<=n;++i){scanf("%lld",&x[i]);if(x[i]==1)cnt1++;}
19         for(int i=1;i<=cnt_prime;++i)f[prime[i]]=prime[i],al[prime[i]]=0;
20         for(int i=1;i<=n;++i)if(x[i]!=1)for(int j=1;j<v[x[i]].size();++j)
21             f[find(v[x[i]][j])]=find(v[x[i]][0]),al[v[x[i]][j]]=1;//,printf("%lld %lld
",v[x[i]][0],v[x[i]][j]);
22         for(int i=1;i<=n;++i)if(x[i]!=1)al[v[x[i]][0]]=1;
23         for(int i=1;i<=cnt_prime;++i)if(al[prime[i]])if(al[find(prime[i])]!=2)
24             al[find(prime[i])]=2,cnt1++;
25         printf("%lld
",(pow(2,cnt1)-2+mod)%mod);
26     }
27 }
View Code

思路积累:

  • 埃筛:求出含有的每种质因子
  • 并查集

T2:y

莫名想到了双向搜索,因为20的范围会很卡但是折半之后就很好,然后就好做了。

可以发现我们要求的路径不限制终点。

那么分别处理以1为起点所能形成的长度为d/2的路径集合和以任意点为起点的路径集合。

然后把两种路径的终点接起来就形成了长度为d的路径。

比脸快23s抢到迷之首杀。

 1 #include<cstdio>
 2 int can[11][99][1028],n,fir[99],l[20000],to[20000],v[20000],cnt,m,d,rev[1028],ans,can2[11][99][1028],al[1048577];
 3 void link(int a,int b,int V){l[++cnt]=fir[a];fir[a]=cnt;to[cnt]=b;v[cnt]=V;}
 4 int main(){
 5     scanf("%d%d%d",&n,&m,&d);
 6     for(int i=1,a,b,V;i<=m;++i)scanf("%d%d%d",&a,&b,&V),link(a,b,V),link(b,a,V);
 7     int lh=d>>1,rh=d-lh,usf=(1<<rh)-1;
 8     can[0][1][0]=1;for(int i=1;i<=n;++i)can2[0][i][0]=1;
 9     for(int len=0,L=1;len<lh;++len,++L)for(int i=1;i<=n;++i)for(int st=0;st<1<<len;++st)if(can[len][i][st])
10         for(int j=fir[i];j;j=l[j])can[L][to[j]][st<<1|v[j]]=1;
11     for(int len=0,L=1;len<rh;++len,++L)for(int i=1;i<=n;++i)for(int st=0;st<1<<len;++st)if(can2[len][i][st])
12         for(int j=fir[i];j;j=l[j])can2[L][to[j]][st<<1|v[j]]=1;
13     for(int i=0;i<1<<lh;++i)for(int j=1;j<=n;++j)if(can[lh][j][i])
14         for(int k=0;k<=usf;++k)if(!al[i<<rh|k]&&can2[rh][j][k])al[i<<rh|k]=1,ans++;
15     printf("%d
",ans);
16 }
View Code

思路积累:

  • 双向搜索:状态数开根

T3:z

31分给暴力了。

+14分单调:只要处理第一个和最后一个就行。x[2]=x[n],n=2;然而考场上没写n=2,T掉了。。。

+20分曲折:二分最早的不能覆盖的段然后就是一次函数。

100分:大模拟。考场上有链表+堆的思路。感觉很不好打就没有打。

事实上的确很不好打,现在还没有A。

思路和下发的std不太一样。

原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/11615361.html