• P7297 [USACO21JAN] Telephone G 另类解发


    一种新的方法,做法类似于 w33z 的毒瘤题,大家可以类比着看一下。

    这道题启示我们什么?对于 (n) 个点向 (m) 个点分别连边,我们可以引入中介来讲 (nm) 条边变成 (n+m) 条边。

    相似的道理,首先考虑如果 (S_{i,i}) 保证为 (1) 怎么做?我们可以将同一个种类的所有相邻两头奶牛的连边。每一个奶牛对于一种颜色,就只需要跟左边最近的和右边最近的连边就可以了(当然如果左边或右边没有这个种类的奶牛就自然不用了)。

    我们回过来再考虑(S_{i,i}) 可能为 (0),也就是说不能再同种类的相邻的两头奶牛建边了。我们给每个点建一个虚点,虚点向这个点连边,我们就可以在同一个种类的所有相邻两头奶牛的虚点连边,每一个奶牛对于一种颜色,就只需要跟左边最近的和右边最近的虚点连边就可以了(当然如果左边或右边没有这个种类的奶牛就自然不用了)。

    相比于分层图的解法,代码有些难写:

    #include<bits/stdc++.h>
    #define log(a) cerr<<"33[32m[DEBUG] "<<#a<<'='<<(a)<<" @ line "<<__LINE__<<"33[0m"<<endl
    #define LL long long
    #define eb emplace_back
    #define SZ(x) ((int)x.size()-1)
    #define ms(a,b) memset(a,b,sizeof a)
    #define F(i,a,b) for(int i=(a);i<=(b);++i)
    #define DF(i,a,b) for(int i=(a);i>=(b);--i)
    using namespace std;
    inline int read(){char ch=getchar(); int w=1,c=0;
    	for(;!isdigit(ch);ch=getchar()) if (ch=='-') w=-1;
    	for(;isdigit(ch);ch=getchar()) c=(c<<1)+(c<<3)+(ch^48);
    	return w*c;
    }
    const int N=1e5+10;
    int b[N],cnt,lst[55][N],f[N];
    bool h[55][55];
    vector<pair<int,int> >v[N];
    queue<int>q;
    int main(){
    	int n=read(),k=read();
    	F(i,1,n){
    		b[i]=read();
    		v[i+n].eb(i,0);
    		if(lst[b[i]][0]){
    			v[i+n].eb(lst[b[i]][lst[b[i]][0]]+n,i-lst[b[i]][lst[b[i]][0]]);
    			v[lst[b[i]][lst[b[i]][0]]+n].eb(i+n,i-lst[b[i]][lst[b[i]][0]]);
    		}lst[b[i]][++lst[b[i]][0]]=i;
    	}
    	F(i,1,k)
    		F(j,1,k){
    			char ch=getchar();
    			for(;ch!='0'&&ch!='1';ch=getchar());
    			h[i][j]=(ch=='1');
    		}
    	F(i,1,n)
    		F(j,1,k)
    			if(h[b[i]][j]){
    				if(!lst[j][0])continue;
    				if(lst[j][1]<=i){
    					int x=upper_bound(lst[j]+1,lst[j]+lst[j][0]+1,i)-lst[j]-1;
    					v[i].eb(lst[j][x]+n,i-lst[j][x]);
    				}
    				if(lst[j][lst[j][0]]>i){
    					int x=upper_bound(lst[j]+1,lst[j]+lst[j][0]+1,i)-lst[j];
    					v[i].eb(lst[j][x]+n,lst[j][x]-i);
    				}
    			}
    	ms(f,0x3f);f[1]=0;
    	q.push(1);
    	while(q.size()){
    		int x=q.front();q.pop();
    		for(auto[fi,se]:v[x]){
    			if(f[x]+se<f[fi]){
    				f[fi]=f[x]+se;
    				q.push(fi);
    			}
    		}
    	}
    	if(f[n]==f[0])puts("-1");
    	else cout<<f[n];
    	return 0;
    }
    
  • 相关阅读:
    HTML Window.document对象
    HTML JavaScript的DOM操作
    HTML 运算符、类型转换
    HTML JavaScript简介
    js对象学习
    理解MySQL数据库覆盖索引
    mysql 索引2
    mysql 索引
    Extjs 使用图标字体来美化按钮)
    MySql数据类型问题
  • 原文地址:https://www.cnblogs.com/zhaohaikun/p/14954058.html
Copyright © 2020-2023  润新知