zoukankan      html  css  js  c++  java
  • HGOI20190811 省常中互测4

      Problem A magic

    给出一个字符串$S$,和数字$n$,要求构造长度为$n$只含有小写字母的字符串$T$,

    使得在$T$中存在删除且仅删除一个子串使得$S=T$成立。

    输出$T$的构造方案数,mod 998244353的值。

    对于$100 \% $的数据 $2  leq n leq 10^{18} , |S| leq 10^6$

    Sol : 考虑$T$合法的条件是和$S$有相同的前缀和相同的后缀,且相同前后缀长度和是$|S|$ 

         若最长公共前缀长度为$0$ ,那么说明$S$和$T$最后$|S|$位相同,合法情况$T$的取值有$26^{n - |S|}$ 种。

      若最长公共前缀长度不为$0$ ,那么说明前半部分至少有$k$是$S$的前缀,后半部分就有$|S| - k $的长度是后缀,这个时候由于倒数$|S| - k$ 个 不能和上一次一样,这个位置只有$25$种可能,其他位置是$26$种可能,这种情况下方案数时$26^{n-|S|-1}$

        最后答案就是$26^n - 26^{n-1} - |S| imes 25 imes 26^{n-|S|-1}$

      注意需要特判$n = |S|$的情况,答案就是$26 ^ n - 1$ 

     复杂度是$O(log_2 n)$

    #include<bits/stdc++.h>
    using namespace std;
    const long long mod=998244353;
    long long n,m;
    char tmp[1000100];
    long long Pow(long long x,long long k)
    {
        if(k<0) return 0ll; 
        if(!k) return 1ll;
        long long res=Pow(x,k/2);
        res=res*res%mod;
        if(k%2) res=res*x%mod;
        return res;
    }
    int main()
    {
        scanf("%lld %s",&n,tmp);
        m=strlen(tmp);
        printf("%lld",(long long)(Pow(26ll,n)-(Pow(26ll,n-m)%mod+(m*25ll%mod)*Pow(26ll,n-m-1)%mod)%mod+mod)%mod);
        return 0;
    }
    A.cpp

       Problem B graph

      给出可重边无自环不保证连通的无向图$G$ ,询问$u $到$v$简单路径上经过边权的最大值最小。

      对于$100\% $ 的数据$n,m,q leq 3 imes 10^5$

           Sol: 建出最小生成树(在建树过程考虑了重边了)。、

        然后用并查集维护连通性。

        最大边权最小等价于在最小生成树树上路径的最大值。

        复杂度就是$O(m log_2 m)$

    # include<bits/stdc++.h>
    using namespace std;
    const int N = 3e5 + 10;
    map<int,int>mp[N]; 
    int g[N][22],d[N][22],dep[N],fc[N],n,m,q;
    vector<pair<int , int> >E[N];
    struct edge{
        int u,v,w;
    };
    vector<edge>Edge;
    bool cmp(edge a,edge b){return a.w < b.w;}
    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;
    }
    void write(int x)
    {
        if (x<0) x=-x,putchar('-');
        if (x>9) write(x/10);
        putchar('0'+x%10);
    }
    void writeln(int x)
    {
        write(x); putchar('
    ');
    }
    int father(int x)
    {
        if (fc[x]==x) return x;
        return fc[x]=father(fc[x]);
    }
    void kruskal()
    {
        sort(Edge.begin(),Edge.end(),cmp);
        for (int i = 1; i <= n; i++) fc[i] = i;
        for (int i = 0; i < Edge.size(); i++) {
            int u=Edge[i].u,v=Edge[i].v,w=Edge[i].w;
            int fx = father(Edge[i].u),fy = father(Edge[i].v);
            if (fx == fy) continue;
            fc[fx] = fy;
            E[u].push_back(make_pair(v,w));
            E[v].push_back(make_pair(u,w));
        } 
    }
    void dfs(int u,int fa)
    {
        dep[u]=dep[fa]+1; g[u][0]=fa;
        for (int i=0;i<E[u].size();i++) {
            int v=E[u][i].first,w=E[u][i].second;
            if (v==fa) continue;
            d[v][0]=w;
            dfs(v,u);
        }
    }
    void init()
    {
        for (int i = 1 ; i<=n ; i++)
            if (!dep[i]) dfs(i,0);
        for (int i = 1; i <= 21 ; i++)
         for (int j = 1; j <= n ; j++)
           g[j][i] = g[g[j][i-1]][i-1],
           d[j][i] = max(d[j][i-1] , d[g[j][i-1]][i-1]);       
    }
    int query(int u,int v)
    {
        int fx = father(u), fy = father(v);
        if (fx != fy) return -1;
        if (dep[u] < dep[v]) swap(u,v);
        int ret = 0;
        for (int i = 21 ; i >= 0 ; i--)
         if (dep[g[u][i]] >= dep[v]) 
            ret = max(ret,d[u][i]),u=g[u][i];
        if (u == v) return ret;
        for (int i = 21 ; i >= 0 ;i--)
         if (g[u][i] != g[v][i]) 
            ret = max(max(ret , d[u][i]) , d[v][i]),
            u = g[u][i] , v = g[v][i];
        return max(max(ret,d[u][0]),d[v][0]);   
    }
    int main()
    {
        n=read();m=read();q=read();
        for (int i=1;i<=m;i++) {
            int u=read(),v=read(),w=read();
            if (mp[u].count(v) != 0) w = min(w , mp[u][v]);
            mp[u][v] = mp[v][u] = w;
        }
        map<int,int>::iterator it;
        for (int i = 1; i <= n ; ++i ) 
            for (it = mp[i].begin() ; it != mp[i].end() ; ++it) 
                Edge.push_back((edge){i , it->first , it->second});
        kruskal(); init();
        while (q--) {
            int u=read(),v=read();
            writeln(query(u,v));
        }
        return 0;
    }
    B.cpp

          Problem C number

      定义不算前导零,只由两个数字构成的数为“好数”,如$101010$, $11111$

           给出$T$个询问,询问$x$至少由几个好数相加组成的(可以同一个数用多次)。

      对于$100\%$的数据$1 leq n leq 10^{18} ,1 leq T leq 100$

      Sol:考虑$01$ , $02$ , $03$ , $04$最多四个数字就可以创造世界了,所以我们只需要判断$3$及以下的情况,剩余情况就输出$4$

      我们可以枚举$C_{10}^{2} = 45$种选择数的方案$mask[i]$来构成这些数,然后用dp验证即可。

      我们只至少这若干个数加起来是多少,我们要还原他为0,才能检验是否合法。

      对于每个三个数累加的方案,我们都有这三个数中任意选2个任意选1个不选这7种子方案,也能获得相同的效果,我们特殊考虑,记录在$Sub[i]$中。

      我们可以预处理出每个个选择数的方案,可以构成哪些最小合法的数(显然这些数都是小于等于$3 imes 9 =27$的)

          设$f[i][j]$表示使用标号为$i$的方案,到达$j$数位上的信息,这个信息是一个3位二进制数,分别表示高位向低位退位为$i , iin[0,2]$是否合法。

      转移的话可以用位运算转移。

      最后如果当前数位为1,并且可以退0位的方案是ok的,那么我们就对对应取数的个数求min即可。(如果无法构成答案就是4了)

      复杂度是$O(T imes C_{45}^{3} imes 18 imes 3 imes 3)$

    # include <bits/stdc++.h>
    # define int long long
    using namespace std;
    int mask[110],f[20010][22],s[55][55][55],val[20010],a[23];
    bool ok[20010][34];
    int size;
    vector<int>Sub[20010];
    signed main()
    {
        for (int i = 0 ; i <= 9 ; i++ )
            for (int j = i + 1 ; j <= 9 ; j++ )
                 mask[++mask[0]] = i * 10 + j;               
        memset(ok, false, sizeof(ok));
        int t = mask[0] ; mask[0] = 0;
        for (int i = 0 ;i <= t ; i++)
            for (int j = i ; j <= t ; j++)
                for (int k = j ; k <= t ;k++) {
                    val[++size] = 3 - (i==0) - (j==0) - (k==0);
                    ok[size][mask[i]/10 + mask[j]/10 + mask[k]/10] = ok[size][mask[i]%10 + mask[j]/10 + mask[k]/10] = true;
                    ok[size][mask[i]/10 + mask[j]%10 + mask[k]/10] = ok[size][mask[i]/10 + mask[j]/10 + mask[k]%10] = true;
                    ok[size][mask[i]%10 + mask[j]%10 + mask[k]/10] = ok[size][mask[i]%10 + mask[j]/10 + mask[k]%10] = true;
                    ok[size][mask[i]/10 + mask[j]%10 + mask[k]%10] = ok[size][mask[i]%10 + mask[j]%10 + mask[k]%10] = true;
                    s[i][j][k] = s[i][k][j] = s[j][i][k] = s[j][k][i] = s[k][i][j] = s[k][j][i] = size;
                    if (s[0][j][k] != size) Sub[size].push_back(s[0][j][k]);
                    if (s[i][0][k] != size) Sub[size].push_back(s[i][0][k]);
                    if (s[i][j][0] != size) Sub[size].push_back(s[i][j][0]);
                    if (s[0][0][k] != size) Sub[size].push_back(s[0][0][k]);
                    if (s[0][j][0] != size) Sub[size].push_back(s[0][j][0]);
                    if (s[i][0][0] != size) Sub[size].push_back(s[i][0][0]);
                    if (s[0][0][0] != size) Sub[size].push_back(s[0][0][0]);
                }               
        int T; scanf("%lld",&T);
        while (T--) {
            memset(f, 0 , sizeof(f));
            int x; scanf("%lld",&x); a[0] = 0;
            while (x) { a[++a[0]] = x%10; x/=10;}
            for (int i = 1; i<= size; i++) f[i][a[0]+1] = 1;
            for (int i = a[0] ; i>=1 ; i--) {
                for (int j = 1; j <= size ; j++) {
                    for (int last = 0 ; last <= 2 ; last++) if (f[j][i+1] & (1<<last)) 
                        for (int to = 0; to <= 2 ; to++) if (last*10 + a[i] - to >= 0 && ok[j][last*10 + a[i] - to]) {
                            f[j][i] |= (1<<to) ;
                        }
                    for (int k = 0 ;k < Sub[j].size() ; k++) {
                            int tmp = Sub[j][k] ;   
                            f[j][i] |= f[tmp][i];
                    }    
                }
            }
            int ans = 4;
            for (int i = 1 ; i <= size ; i++) if (f[i][1] & 1)   ans = min(ans , val[i]); 
            printf("%lld
    ",ans);
        }
        return 0;
    }
    C.cpp
  • 相关阅读:
    vector与iterator的一些用法
    动态规划 hdu 1024
    dfs bfs hdu 1045
    hdu 2795
    poj 2828
    线段树染色
    线段树比大小
    A
    ?线程局部变量
    JRE、JDK、JVM 及 JIT
  • 原文地址:https://www.cnblogs.com/ljc20020730/p/11335626.html
Copyright © 2011-2022 走看看