HGOI20190706 题解

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('\n');
    }
    return 0;
}
easy.cpp

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,即$j\leq i-2$ 
  • 不能有前导0,如果当前转移必然会造成前导零的,那么此次转移不合法,即$s_{i+1} \neq "0" $
  • 令最后编码长度尽可能短,需要$c_i \neq c_{i+1}$ 即$s_j \neq s_i $

所以我们就可以写出一个转移方程 $f_i = \left\{\begin{matrix} \sum\limits_{j=0} ^ {i-2} (s_i \neq s_j) \times f_j & s_{i+1}\neq "0"\\  0 &  s_{i+1}= "0" \end{matrix}\right.$ 

上述转移可以使用前缀和优化,令$sum_{i,j} = \sum\limits_{k=0} ^ {i} (s_k = j)\times f_k ,g_i = \sum\limits_{j=0}^{i} f_j$ 

上述转移可以写成: $f_i = \left\{\begin{matrix} g_{i-2} - sum_{i-2,s_i} \ & s_{i+1}\neq "0"\\   0 &  s_{i+1}= "0" \end{matrix} \right. $

同时注意$sum_{i,j} 和 g_{i}$ 的同步更新即可。

复杂度就是$O (9 \times 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\n",f[n]);
    return 0;
}
hard.cpp

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\times 10^5 c_{i,j},w\leq 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('\n');
    return 0;
 }
hammer.cpp

 

posted @ 2019-07-06 14:31  ljc20020730  阅读(167)  评论(0编辑  收藏  举报