zoukankan      html  css  js  c++  java
  • 开学考试题2:words(暴力+状压)

    题目:

     注意:

    这里的范围是n*m<=1e5!!!

    分析:

    前面的小数据可以用n^2 * m的暴力过掉(其实后面也可以)

    暴力100

    #include<bits/stdc++.h>
    using namespace std;
    #define N 100005
    #define ll long long
    int m;
    ll t[N],n;
    vector<char> s[N];
    void work1()
    {
        char ch[5]; int a;
        for(int i=1;i<=n;i++){
            scanf("%s",ch);
            if(ch[0]=='x') a=1;
            if(ch[0]=='y') a=2;
            if(ch[0]=='z') a=3;
            t[a]++;
        }
        ll ans=0;
        for(int i=1;i<=3;i++) ans+=t[i]*(t[i]-1)/2;
        printf("%lld
    %lld
    ",n*(n-1)/2-ans,ans);
    }
    void work2()
    {
        for(int i=0;i<=m-1;i++) printf("0
    ");
        printf("%lld
    ",n*(n-1)/2);
    }
    char tt[N];
    int main()
    {
        freopen("words.in","r",stdin);
        freopen("words.out","w",stdout);
        scanf("%lld%d",&n,&m);
        if(m==1) { work1(); return 0; }
        int fl=1;
        for(int i=1;i<=n;i++){
            scanf("%s",tt);
            for(int j=0;j<m;j++)
             s[i].push_back(tt[j]);
            if(i==1) continue;
            for(int j=0;j<s[i].size();j++)
            if(s[i][j]!=s[i-1][j]) { fl=0; break; }
        }
        if(fl) { work2(); return 0; }
        for(int i=1;i<=n;i++){
            for(int j=i+1;j<=n;j++){
                int cnt=0;
                for(int k=0;k<=m-1;k++)
                 if(s[i][k]==s[j][k]) cnt++;
                t[cnt]++;
            }
        }
        for(int i=0;i<=m;i++) printf("%lld
    ",t[i]);
        return 0;
    }
    /*
    8 1
    x 
    y
    y
    z
    y
    x
    x
    x
    
    4 3
    xyz
    xyz
    zzx
    xzz
    
    4 4
    xyzx
    xyzx
    xyzx
    xyzx
    */
    暴力

    单独处理数据4和数据5,也比较简单。

    但是看了题解发现,对于m较小的点应该用状压dp实现。

    状压dp:

    有三种字母:x,y,z,所以应该用三进制保存字符串的状态,要求的是相似度一定时的对数,所以定义dp[ s ][ k ]为状态为s,相似度为k的对数。

    初始化:dp[ x ][ m ]=s[ x ]    s是原串。

    转移:dp[ s' ][ k-1 ]+=dp[ s ][ k ]  ,s'是改变1个字符后的状态,改变了一个字符,相似度就应该-1。

    但是会发现,对于这组数据:xyz,xyy,xyx

    dp[ xyy ][ 2 ]+=dp[ xyz ][ 3 ];(枚举xyz时把z改成y去更新xyy相似度为2的方案)

    dp[ xyx ][ 1 ]+=dp[ xyy ][ 2 ];(枚举xyy时把y改成x去更新xyx相似度为1的方案)

    明显dp[ xyx ][ 1 ]==0 ,但是通过上述顺序更新处理=1。

    是哪里出了问题呢?因为我们把xyz的第三位改变了两次,当成了整个串改变了两个位置!!!

    所以应该固定每一个串改变的位置(即最外层枚举要修改的位置),并且一个值被改变后,不能在同一层循环里面再去更新别的值。

    所以要用一个ff数组临时储存一下再来转移

    代码细节很多。。。

    下面是std,自己并没有打

    void Work1(int n, int m) {
        for (int i = 1; i <= n; i++) {
            int now = 0;
            for (int j = 1; j <= m; j++) {
                now *= 3;
                char k;
                for (k = getchar(); k <= 32; k = getchar());
                now += k - 'x';
            }
            ss[now]++;
        }
        mi3[0] = 1;
        for (int i = 1; i <= m; i++)    mi3[i] = mi3[i - 1] * 3;
        for (int i = 0; i < mi3[m]; i++)    dp1[i][m] = ss[i];
        for (int i = 0; i < m; i++) {
            memcpy(dp, dp1, sizeof dp);
            for (int j = 0; j < mi3[m]; j++) {
                int s1 = j / mi3[i] % 3, s2 = j - s1 * mi3[i];
                for (int t = 0; t < 3 * mi3[i]; t += mi3[i])
                    if (t != s1 * mi3[i])
                    for (int p = m - i; p <= m; p++)    dp[s2 + t][p - 1] += dp1[j][p];
            }
            memcpy(dp1, dp, sizeof dp);
        }
        for (int i = 0; i < mi3[m]; i++)
            for (int p = 0; p <= m; p++)
                ans[p] += 1LL * ss[i] * dp1[i][p];
        ans[m] = ans[m] - n;
        for (int i = 0; i <= m; i++)    ans[i] /= 2;
    }
    std
  • 相关阅读:
    ASP.NET MVC 重点教程一周年版 第二回 UrlRouting
    ASP.NET MVC 重点教程一周年版 第三回 Controller与View
    DynamicData for Asp.net Mvc留言本实例 下篇 更新
    Asp.net MVC视频教程 18 单选与复选框
    使用ASP.NET MVC Futures 中的异步Action
    ASP.NET MVC RC 升级要注意的几点
    ATL、MFC、WTL CString 的今生前世
    msvcprt.lib(MSVCP90.dll) : error LNK2005:已经在libcpmtd.lib(xmutex.obj) 中定义
    关于Windows内存的一些参考文章
    Windows访问令牌相关使用方法
  • 原文地址:https://www.cnblogs.com/mowanying/p/11482018.html
Copyright © 2011-2022 走看看