TopCoder 1643 PossibleOrders

题目链接

题目大意

给定一些形如 A = B 的等式,问有几种在这些等式之间添加符号( = , < , > )的方法使得不等式成立。

思路

首先肯定可以想到并查集,将所有相等的数合并到一起考虑。
再可以想到 > 其实是没有用的,因为大于号不可能和小于号同时发生( a < b > c 的形式就已经把等式锁死了)。
那么问题就转化成了,一些不同的数,在他们之间安排上等于号和小于号的方案数。
= 的意义转化为“分组”,问题就又转化成了:将 n 个不同的数划分成有区别的若干组的方案数(组与组之间使用 < 号连接,故组的顺序是要被考虑的)”
考虑DP, f [ i ] [ j ] 表示前 i 个数分成 j 个不同的组的方案数。
考虑转移,第 i 个数有两种方式被放入

  • 插入到前面的某一组中,方案数 j f [ i 1 ] [ j ] ,因为前面已经有 j
  • 自成一组,并插入到某个地方,方案数 j f [ i 1 ] [ j 1 ] ,因为原先 j 1 组会有 j 个空位置让你插入。

另一种思路

并查集依然是并查集,将一堆数缩成一个数。
依然是那个DP的意义,考虑将 n 个数划分成有区别的若干组的方案数。
再回想斯特林数的组合意义:将 n 个球装入 m 个不可区分的盒子的方案数。
这两个有什么区别呢?一个盒子有区别,一个无区别。那么就是相差了一个排列。
答案为 i = 1 n S [ n ] [ i ] i !

代码(DP)

#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<map>
#include<queue>
#include<vector>
#include<stack>
#include<set>
#include<cctype>
#define pa pair<int,int>
#define INF 0x3f3f3f3f
#define inf 0x3f
#define fi first
#define se second
#define mp make_pair
#define ll long long
#define ull unsigned long long
#define pb push_back

using namespace std;

inline ll read()
{
    long long f=1,sum=0;
    char c=getchar();
    while (!isdigit(c)) {if (c=='-') f=-1;c=getchar();}
    while (isdigit(c)) {sum=sum*10+c-'0';c=getchar();}
    return sum*f;
}
const int MAXN=20; 
int fa[MAXN];
int find(int x)
{
    if (fa[x]!=x)
        fa[x]=find(fa[x]);
    return fa[x];
}
pa get_num(string s)
{
    int pos=0;
    for (int i=0;i<s.size()&&!pos;i++)
        if (s[i]=='=')
            pos=i;
    pa re;
    for (int i=0;i<pos;i++)
        re.fi=re.fi*10+s[i]-'0';
    for (int i=pos+1;i<s.size();i++)
        re.se=re.se*10+s[i]-'0';
    re.fi++,re.se++;
    return re;  
}
ll f[MAXN][MAXN];
struct PossibleOrders{
    long long howMany(int num,vector<string> facts)
    {
        for (int i=1;i<=num;i++)
            fa[i]=i;
        vector<string>::iterator it;
        for (it=facts.begin();it!=facts.end();it++)
        {
            pa nums=get_num(*it);
            int f1=find(nums.fi),f2=find(nums.se);
            if (f1!=f2) fa[f1]=f2;
        } 
        int tot=0;
        f[0][0]=1;
        for (int i=1;i<=num;i++)
        {
            if (find(i)!=i) continue;
            tot++;
            for (int j=1;j<=tot;j++)
                f[tot][j]=(f[tot-1][j-1]+f[tot-1][j])*j;    
        }
        ll ans=0;
        for (int i=1;i<=tot;i++)
            ans+=f[tot][i];
        return ans;
    }
};

代码(斯特林数)

#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<map>
#include<queue>
#include<vector>
#include<stack>
#include<set>
#include<cctype>
#define pa pair<int,int>
#define INF 0x3f3f3f3f
#define inf 0x3f
#define fi first
#define se second
#define mp make_pair
#define ll long long
#define ull unsigned long long
#define pb push_back

using namespace std;

inline ll read()
{
    long long f=1,sum=0;
    char c=getchar();
    while (!isdigit(c)) {if (c=='-') f=-1;c=getchar();}
    while (isdigit(c)) {sum=sum*10+c-'0';c=getchar();}
    return sum*f;
}
const int MAXN=20;
int fa[MAXN];
int find(int x)
{
    if (fa[x]!=x) fa[x]=find(fa[x]);
    return fa[x];
}
pa get_num(string s)
{
    int pos=0;
    for (int i=0;!pos;i++)
        if (s[i]=='=')
            pos=i;
    pa re;
    for (int i=0;i<pos;i++)
        re.fi=re.fi*10+s[i]-'0';
    for (int i=pos+1;i<s.size();i++)
        re.se=re.se*10+s[i]-'0';
    re.fi++,re.se++;
    return re;
}
long long S[MAXN][MAXN];
long long fac[MAXN];
struct PossibleOrders{
    long long howMany(int num,vector<string> facts)
    {
        vector<string>::iterator it;
        for (int i=1;i<=num;i++)
            fa[i]=i;
        for (it=facts.begin();it!=facts.end();it++)
        {
            pa nums=get_num(*it);
            int f1=find(nums.fi),f2=find(nums.se);
            if (f1!=f2)
                fa[f1]=f2;
        }
        int n=0;
        for (int i=1;i<=num;i++)
            if (find(i)==i)
                n++;
        fac[0]=1;
        for (int i=1;i<=n;i++)
            fac[i]=fac[i-1]*i;
        S[1][1]=1;
        for (int i=2;i<=n;i++)
            for (int j=1;j<=i;j++)
                S[i][j]=S[i-1][j]*j+S[i-1][j-1];
        ll ans=0;
        for (int i=1;i<=n;i++)
            ans+=fac[i]*S[n][i];
        return ans;
    }
};

猜你喜欢

转载自blog.csdn.net/szh_0808/article/details/81000285