开学考试题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\n%lld\n",n*(n-1)/2-ans,ans);
}
void work2()
{
    for(int i=0;i<=m-1;i++) printf("0\n");
    printf("%lld\n",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\n",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

猜你喜欢

转载自www.cnblogs.com/mowanying/p/11482018.html