Problem A 质因数
设f(x) 表示x的不同质因子个数,给出T组x,询问f(x)的值。
对于100%的数据 $x,T leq 10^5 $
Sol : 第一遍欧拉筛,并记录下每个数的最小质因数。
然后对于每个询问直接O(1) 映射它的最小质因数,然后不断除掉。
最差情况是2的幂次,复杂度应该是$O(n log_2 n)$

# include <bits/stdc++.h> using namespace std; const int N=1e6+10; bool is_pr[N]; int pr[N],dr[N]; inline int read() { int X=0,w=0; char c=0; while(c<'0'||c>'9') {w|=c=='-';c=getchar();} while(c>='0'&&c<='9') X=(X<<3)+(X<<1)+(c^48),c=getchar(); return w?-X:X; } inline void write(int x) { if (x<0) x=-x,putchar('-'); if (x>9) write(x/10); putchar(x%10+'0'); } void EouLaSha(int Lim) { memset(is_pr,true,sizeof(is_pr)); is_pr[1]=false; for (int i=2;i<=Lim;i++) { if (is_pr[i]) pr[++pr[0]]=i,dr[i]=i; for (int j=1;j<=pr[0]&&i*pr[j]<=Lim;j++) { is_pr[i*pr[j]]=false; dr[i*pr[j]]=pr[j]; if (i%pr[j]==0) break; } } } int fun(int x) { int cnt=0; while (x!=1) { ++cnt; int t=dr[x]; while (x%t==0) x/=t; } return cnt; } int main() { EouLaSha(1e6); int T=read(); while (T--) { int x=read(); write(fun(x)); putchar(' '); } return 0; }
Problem B 编码
定义P(A)表示对于一个数字串编码值,显然A可以由$b_i$ 个 $c_i$字符不断拼接组成 。
则P(A) 为$b_i和$c_i$顺次相连所组成的字符串。如P("111222333") = "132333" 表示"1"出现3次,"2"出现3次,"3"出现3次
其中$b_i$不允许有前导零,在上述限制下令最后的长度尽可能短。
现在给出P(A)的值,询问A有多少种不同的解。
对于100%的数据 $ length(A)leq 10^5$
Sol : 这道题是一个Dp题。
设$f_i$ 表示到第$i$位置为止$[1,i]$所构成子串中,可能的解的个数,最后$f_n$就是解。
考虑$f_i$从$f_j$转移过来,即$[j+1,i]$可以构成一组$b_i , c_i$。
考虑这个转移的限制:
- [j+1,i]长度应该大于等于2,即$jleq i-2$
- 不能有前导0,如果当前转移必然会造成前导零的,那么此次转移不合法,即$s_{i+1} eq "0" $
- 令最后编码长度尽可能短,需要$c_i eq c_{i+1}$ 即$s_j eq s_i $
所以我们就可以写出一个转移方程 $f_i = left{egin{matrix} sumlimits_{j=0} ^ {i-2} (s_i eq s_j) imes f_j & s_{i+1} eq "0"\ 0 & s_{i+1}= "0" end{matrix} ight.$
上述转移可以使用前缀和优化,令$sum_{i,j} = sumlimits_{k=0} ^ {i} (s_k = j) imes f_k ,g_i = sumlimits_{j=0}^{i} f_j$
上述转移可以写成: $f_i = left{egin{matrix} g_{i-2} - sum_{i-2,s_i} & s_{i+1} eq "0"\ 0 & s_{i+1}= "0" end{matrix} ight. $
同时注意$sum_{i,j} 和 g_{i}$ 的同步更新即可。
复杂度就是$O (9 imes n) $

# include<bits/stdc++.h> # define int long long using namespace std; const int N=1e6+10; const int mo=998244353; int f[N]; int n,sum[N][15],g[N]; char s[N]; signed main() { scanf("%s",s+1); int n=strlen(s+1); if (!(s[1]^48)){ puts("0"); return 0;} memset(f,0,sizeof(f)); f[0]=1; g[0]=1; f[1]=0; g[1]=1; for (int i=2;i<=n;i++) { for (int j=0;j<=9;j++) sum[i][j]=sum[i-1][j]; if (s[i+1]=='0') { f[i]=0; g[i]=g[i-1]+f[i]; sum[i][s[i]-'0']=(sum[i][s[i]-'0']+f[i])%mo; continue; } f[i]+=g[i-2]; f[i]-=sum[i-2][s[i]-'0']; f[i]=(f[i]%mo+mo)%mo; g[i]=(g[i-1]+f[i])%mo; sum[i][s[i]-'0']=(sum[i][s[i]-'0']+f[i])%mo; } printf("%lld ",f[n]); return 0; }
Problem C 八卦阵
给出一幅有向图,对于每个点有8种状态$f_{u,0} ... f_{u,7} $i$秒钟u的状态为$b_{u,(i-1) mod 8} in [1,8]$
对于两个点的状态$i,j$都存在一个复杂度$c_{i,j}$
第i秒钟通过边E=(u,v,w)的代价是$w + c_{b_{u,(i-1) mod 8},b_{v,(i-1) mod 8}} $
问从1号点走到底n号点的最小代价是多少。
对于100%的数据 $n leq 10^5 ,m leq 3 imes 10^5 c_{i,j},wleq 10^4$
Sol : 考虑Dijkstra求最短路在松弛更新的时候把代价改成上面的的权值。
对于每个节点,记录下访问他的时间,然后考虑(u,v,w)这条边的松弛
考虑时间是按照$8$一个循环,还是比较小的,可以使用$dist_{i,j}$表示当前时间是$i$ 从1访问到$j$号点的最小代价。
使用$d_{time - 1,u}$ 来更新$d_{time,v}$ ,注意到下标需要对8取模。
复杂度就是$O(n log_2 n)$

# include<bits/stdc++.h> # define int long long using namespace std; const int N=1e5+10,M=3e5+10; struct Edge{ int pre,to,w; }a[M]; int n,m; int c[15][15],b[N][15]; int head[N],tot,d[10][N]; inline int read() { int X=0,w=0; char c=0; while(c<'0'||c>'9') {w|=c=='-';c=getchar();} while(c>='0'&&c<='9') X=(X<<3)+(X<<1)+(c^48),c=getchar(); return w?-X:X; } inline void write(int x) { if (x<0) x=-x,putchar('-'); if (x>9) write(x/10); putchar(x%10+'0'); } void adde(int u,int v,int w) { a[++tot].pre=head[u]; a[tot].to=v; a[tot].w=w; head[u]=tot; } struct rec{ int len,id,time; }; struct cmp { bool operator () (rec a,rec b) { return a.len>b.len; } }; priority_queue<rec,vector<rec>,cmp>q; int dijkstra(int s,int t) { memset(d,0x3f,sizeof(d)); d[0][s]=0; q.push((rec){0,s,0}); while (!q.empty()) { rec u=q.top();q.pop(); for (int i=head[u.id];i;i=a[i].pre) { int tim=(u.time+1)%8,v=a[i].to; int cost=a[i].w+c[b[u.id][((tim-1)%8+8)%8]][b[v][((tim-1)%8+8)%8]]; if (d[tim][v]-cost>d[((tim-1)%8+8)%8][u.id]) { d[tim][v]=d[((tim-1)%8+8)%8][u.id]+cost; q.push((rec){d[tim][v],v,tim}); } } } int ans=0x3f3f3f3f; for (int i=0;i<=7;i++) ans=min(ans,d[i][t]); return ans; } signed main() { scanf("%lld%lld",&n,&m); for (int i=1;i<=8;i++) for (int j=1;j<=8;j++) c[i][j]=read(); for (int i=1;i<=n;i++) for (int j=0;j<=7;j++) b[i][j]=read(); for (int i=1;i<=m;i++) { int u=read(),v=read(),w=read(); adde(u,v,w); } int ans=dijkstra(1,n); write(ans); putchar(' '); return 0; }