2020杭电多校第2场

1题:并查集

题解:
我们先将我们的亮度从大到小排序,然后我们依次加入x点,并且加入和这个点相连的所有点,如果新加入的y点的亮度大于x点,那么我们就把他们合并。在之后我们计算答案的时候,对于x节点,当需要删除他的时候他已经减去了他的父亲节点的亮度了,所以只需要再减去剩下的 d − d f a t h e r d-d_{father} ddfather的答案。所以最后求一下和就可以了。

#include 
using namespace std;
typedef long long ll;
const int N=100010;
int d[N],f[N],fa[N],vis[N],num[N];
vector<int> g[N];
int cmp(int a,int b)
{
    return d[a]>d[b];
}
int find(int x)
{
    if(f[x]==x) return f[x];
    return f[x]=find(f[x]);
}
signed main()
{
    int t; scanf("%d",&t);
    while(t--){
        int n,m; scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) g[i].clear();
        for(int i=1;i<=n;i++) {
            scanf("%d",&d[i]);
            f[i]=i;
            vis[i]=fa[i]=0;
            num[i]=i;
        }
        sort(num+1,num+1+n,cmp);
        for(int i=1;i<=m;i++) {
            int a,b; scanf("%d%d",&a,&b);
            g[a].push_back(b);
            g[b].push_back(a);
        }
        for(int i=1;i<=n;i++){
            int x=num[i];
            vis[x]=1;
            for(auto it:g[x]){
                if(!vis[it]) continue;
                int fy=find(it);
                if(fy==x) continue;
                fa[fy]=f[fy]=x;
            }
        }
        ll res=0;
        for(int i=1;i<=n;i++) res+=d[i]-d[fa[i]];
        printf("%lld\n",res);
    }
}

6题:哈希

题解:
双哈希过去。因为我们只是把一个1翻成了0,所以枚举C数组遇见0就把他翻转过来看是不是hash值相等,如果相等则答案就是这一位。

#include
#define int long long
using namespace std;
const int mod=1e9+9,mod1=1e9+7,N=2e6+10;
int f[N],f1[N],na,nb,nc,sa,sb,sc,sa1,sb1,sc1,a[N],b[N],c[N];
void solve(){
    scanf("%lld",&na);
    for(int i=1;i<=na;i++)    scanf("%lld",&a[i]);
    scanf("%lld",&nb);
    for(int i=1;i<=nb;i++)    scanf("%lld",&b[i]);
    scanf("%lld",&nc);
    for(int i=1;i<=nc;i++)    scanf("%lld",&c[i]);
    sa=sb=sc=0; sa1=sb1=sc1=0;
    for(int i=1;i<=na;i++)    sa=(sa+f[i]*a[i])%mod;
    for(int i=1;i<=nb;i++)    sb=(sb+f[i]*b[i])%mod;
    for(int i=1;i<=nc;i++)    sc=(sc+f[i]*c[i])%mod;
    for(int i=1;i<=na;i++)    sa1=(sa1+f1[i]*a[i])%mod1;
    for(int i=1;i<=nb;i++)    sb1=(sb1+f1[i]*b[i])%mod1;
    for(int i=1;i<=nc;i++)    sc1=(sc1+f1[i]*c[i])%mod1;
    for(int i=1;i<=nc;i++)    if(c[i]==0){
            int tmp=(sc+f[i])%mod,tmp1=(sc1+f1[i])%mod1;
            if(tmp==(sa*sb)%mod&&tmp1==(sa1*sb1)%mod1){
                printf("%lld\n",i);    break;
            }
        }
}
signed main(){
    f[1]=1,f[2]=2;
    for(int i=3;i<N;i++)    f[i]=(f[i-1]+f[i-2])%mod;
    f1[1]=1,f1[2]=2;
    for(int i=3;i<N;i++)    f1[i]=(f1[i-1]+f1[i-2])%mod1;
    int T; cin>>T; while(T--) solve();
    return 0;
}

10题:DFS

题解:
直接爆搜,正向搜wa了,但是反向可以过,队友给我说的是机组原理的一些知识,但是我不会,呜呜呜。

#include 
using namespace std;
typedef long long ll;
const int N=100;
int n,m;
int f[N][N][5],cnt[N];
ll res;
void dfs(int x,int a,int b,int c,int d)
{
    if(x<1){
        ll tmp=1LL*a*b*c*d;
        res=max(res,tmp);
        return;
    }
    if(!cnt[x]){
        dfs(x-1,a,b,c,d);
        return;
    }
    for(int i=1;i<=cnt[x];i++) dfs(x-1,f[x][i][1]+a,f[x][i][2]+b,f[x][i][3]+c,f[x][i][4]+d);
}
signed main()
{
    int t; scanf("%d",&t);
    while(t--){
        res=0;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++) cnt[i]=0;
        for(int i=1;i<=n;i++){
            int tmp; scanf("%d",&tmp);
            cnt[tmp]++;
            for(int j=1;j<=4;j++) scanf("%d",&f[tmp][cnt[tmp]][j]);
        }
        dfs(m,100,100,100,100);
        printf("%lld\n",res);
    }
}

12题:序列自动机+DP

题解:
序列自动机预处理出当前位置 i i i距离最近的字母 j j j的最近下标。
我们定义 f i , j f_{i,j} fi,j为B数组[1…i]这段字符串和A数组[l,r]这段字符串匹配到 L C S LCS LCS的长度为 j j j的时候所需要的A的数组最小下标 x x x, ( l < = x < = r ) (l<=x<=r) l<=x<=r也就是题解中的最小前缀和。dp函数方程式中当我们匹配的x的位置小于r的时候 n x t [ f [ i − 1 ] [ j − 1 ] + 1 ] [ b [ i ] − ′ a ′ ] nxt[f[i-1][j-1]+1][b[i]-'a'] nxt[f[i1][j1]+1][b[i]a],需要 f [ i − 1 ] [ j − 1 ] + 1 f[i-1][j-1]+1 f[i1][j1]+1,因为我们当前位置也可能是这个字母,就会发生错误。最后我们反向循环找最长的 L C S LCS LCS因为我们答案是 l e n a + l e n b − 2 ∗ L C S lena+lenb-2*LCS lena+lenb2LCS,所以需要保证 L C S LCS LCS最大。

#include 
using namespace std;
const int N=1e5+10;
const int INF=0x3f3f3f3f;
int f[50][50];
char a[N],b[N];
struct sub_AM{
    int nxt[N][30];
    void init(){
        int l=strlen(a+1);
        for(int i=0;i<26;i++) nxt[l][i]=l+1;
        nxt[l][a[l]-'a']=l;
        for(int i=l-1;i>=1;i--){
            for(int j=0;j<26;j++){
                nxt[i][j]=nxt[i+1][j];
            }
            nxt[i][a[i]-'a']=i;
        }
    }
//    bool find(char *t){
//        int pos=-1;
//        int l=strlen(t);
//        for(int i=0;i
//            pos=nxt[pos+1][t[i]-'a'];
//            if(pos==INF) return 0;
//        }
//        return 1;
//    }
}solve;
signed main()
{
    int t; scanf("%d",&t);
    while(t--){
        scanf("%s",a+1);
        scanf("%s",b+1);
        int lenb=strlen(b+1);
        solve.init();
        int q; scanf("%d",&q);
        while(q--) {
            int l, r;
            scanf("%d%d", &l, &r);
            memset(f,INF,sizeof f);
//            f[0][0]=l-1;
//            for(int i=1;i<=lenb;i++) f[i][0]=nxt[l][b[i]-'a']-1;
            for(int i=1;i<=lenb;i++) f[i][1]=solve.nxt[l][b[i]-'a'];
            for (int i = 1; i <= lenb; i++) {
                for (int j = 1; j <= i; j++) {
                    if(f[i-1][j]<=r) f[i][j]=min(f[i][j],f[i-1][j]);
                    if(f[i-1][j-1]<r) f[i][j]=min(f[i][j],solve.nxt[f[i-1][j-1]+1][b[i]-'a']);
                }
            }
            int tmp=0;
            for(int i=lenb;i>0;i--){
                if(f[lenb][i]<=r) {
                    tmp=i;
                    break;
                }
            }
//            cout<<"tmp : "<
            int res=(r-l+1+lenb)-2*tmp;
            printf("%d\n",res);
        }
    }
}

你可能感兴趣的:(过程)