EZ 2018 05 06 NOIP2018 慈溪中學集訓隊互測(五)

享受爆零的快感php

老葉原本是讓初三的打的,而後我SB的去湊熱鬧了html

TM的T2寫炸了(去你妹的優化),T1連-1的分都忘記判了,T3理所固然的不會數組

光榮革命啊!優化

T1

思惟圖論題,CHJ dalao給出了正解但-1輸成0了緬懷spa

並且這題不能用讀優玄學code

思路也很新奇,先跑一遍MST,判斷是否有無解的狀況htm

而後看一下MST中與1相連的邊有幾條get

若是小於k那麼咱們把全部與1相連的邊減上一個值使它們優先被選,而後跑MSTstring

大於k就加上去便可it

注意到這個值能夠二分,所以不停作MST便可

CODE

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=5005,M=100005;
const double EPS=1e-5;
struct data
{
    int l,r,s;
    double add;
}a[M];
int n,m,k,cnt,father[N],tot;
long long ans;
inline bool comp(data a,data b)
{
    return a.s+a.add<b.s+b.add;
}
inline int getfather(int k)
{
    return father[k]==k?k:father[k]=getfather(father[k]);
}
inline int MST(double x)
{
    register int i; int res=0,tot=0;
    for (i=1;i<=m;++i)
    if (a[i].l==1||a[i].r==1) a[i].add=x;
    sort(a+1,a+m+1,comp);
    for (i=1;i<=n;++i)
    father[i]=i; ans=0;
    for (i=1;i<=m;++i)
    {
        int fx=getfather(a[i].l),fy=getfather(a[i].r);
        if (fx!=fy)
        {
            if (a[i].l==1||a[i].r==1) ++res;
            ans+=a[i].s; ++tot;
            father[fx]=fy;
        }
    }
    if (tot!=n-1) return -1;
    return res;
}
int main()
{
    freopen("path.in","r",stdin); freopen("path.out","w",stdout);
    register int i;
    scanf("%d%d%d",&n,&m,&k);
    for (i=1;i<=m;++i)
    {
        scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].s);
        if (a[i].l==1||a[i].r==1) ++tot;
    }
    if (tot<k||MST(0)==-1) { puts("-1"); return 0; }
    double l=-100000.0,r=100000.0;
    while (r-l>EPS)
    {
        double mid=(l+r)/2.0; 
        int t=MST(mid);
        if (t==k) { printf("%lld",ans); break; }
        if (t>k) l=mid; else r=mid;
    }
    return 0;
}

T2

這麼小的數據範圍,就是套路的狀壓DP

只有我一我的想到記憶化搜索暴力玄學搜索麼

好吧又是我ZZ了

首先發現n的範圍只有15,果斷狀壓成01串表示第幾個串選或不選

然後預處理一個數組g[i][j]表示當t[i]上的字符爲j時,與其它串的匹配狀況(用二進制下壓縮01串表示)

例如,四個串爲

?a?
ab?
aa?
??b

例如

  • g[2]['a']=1101(與第四個,第三個,第一個串分別匹配)=13

  • g[1]['a']=1111=15

而後咱們設DP數組f[i][j]表示匹配到第i位時(第i位還沒有匹配)全部串的匹配狀況爲j(二進制下的01串)時方案總數

則有f[i][j]能夠轉移出

f[i+1][j&g[i][ch]]+=f[i][j]('a'<=ch<='z')

由於這裏只要一個位置不匹配那就整個串都不匹配,所以只有兩邊都是1才知足要求

最後ans+=全部j的1的個數剛好爲k個的f[len+1][j]

C++沒有以字符爲下標的數組,所以全部字符減去'a'便可

CODE

#include<cstdio>
#include<cstring>
using namespace std;
const int N=20,D=50,mod=1000003;
int g[D+5][30],f[D+5][(1<<N+1)+5],n,k,ans,t;
char s[N][55],ch;
inline int count(int x)
{
    int tot=0;
    while (x) tot+=x&1,x>>=1;
    return tot;
}
int main()
{
    freopen("question.in","r",stdin); freopen("question.out","w",stdout);
    register int i,j; scanf("%d",&t);
    while (t--)
    {
        memset(f,0,sizeof(f));
        memset(g,0,sizeof(g));
        scanf("%d%d",&n,&k);
        for (i=1;i<=n;++i)
        scanf("%s",s[i]+1); int len=strlen(s[1]+1);
        for (i=1;i<=len;++i)
        for (ch='a';ch<='z';++ch)
        for (j=1;j<=n;++j)
        if (s[j][i]=='?'||ch==s[j][i]) g[i][ch-'a']|=1<<j-1;
        f[1][(1<<n)-1]=1; ans=0;
        for (i=1;i<=len;++i)
        for (j=0;j<1<<n;++j)
        if (f[i][j]) for (ch='a';ch<='z';++ch)
        f[i+1][j&g[i][ch-'a']]=(f[i+1][j&g[i][ch-'a']]+f[i][j])%mod;
        for (i=0;i<1<<n;++i)
        if (count(i)==k) ans=(ans+f[len+1][i])%mod;
        printf("%d\n",ans);
    }
    return 0;
}

T3

這就是傳說中的神題麼

暴力的想法都是有的,可是就是剛不出來(只有YZC dalao拿了2分)

標算是DP+KMP+矩陣乘法(快速冪),仍是不可食用的

想要標算的同窗看BZOJ1009黃學長題解

相關文章
相關標籤/搜索