牛客2020多校round2

2 篇文章 0 订阅
1 篇文章 0 订阅

先更第二场。第一场题解看哭了,不太全。

题目链接

https://ac.nowcoder.com/acm/contest/5667#question

A.All with Pairs

题意

f ( s 1 , s 2 ) f(s1,s2) f(s1,s2)定义为一个最大的数i, s 1... i = t ∣ t ∣ − i + 1... ∣ t ∣ s_{1...i}=t_{|t|-i+1...|t|} s1...i=tti+1...t。就是s和t的最长公共前后缀长度。给n个字符串,完了求: ∑ i = 1 n ∑ j = 1 n f ( s i , s j ) 2 (   m o d   998244353 ) \sum_{i=1}^{n} \sum_{j=1}^{n} f\left(s_{i}, s_{j}\right)^{2}(\bmod 998244353) i=1nj=1nf(si,sj)2(mod998244353)

吐槽

这道题其实并不太难。但是场上过得人不多,完了我们没看,我觉得看了是能想出来的。

题解

答题思路是可以线性的枚举每个前缀,看看有多少个后缀和这个前缀相同(记作 c n t i cnt_i cnti),这个字符串哈希就能搞定。完了答案加上这个前缀长度的平方乘上后缀个数就完了。但是这样不一定保证这些配对中这个前缀长度最大。现在想知道这个前缀能匹配,且最长的时候有几个后缀。然后发现只要一个前缀能匹配上一个后缀,那么这个前缀的next也能匹配上后缀的后缀。所以next那个地方应该减掉这个前缀的匹配数(这些匹配数在next那里多算了,因为在那里next并不是最长的前后缀)。注意一个i值在 n e x t i next_i nexti那里减一次,因为现在这个 c n t i cnt_i cnti已经包含了之后的多算的了。 n e x t i next_i nexti和kmp里的略有不同。这里表示1~i的最长公共前后缀长度。

AC代码(next板子)

#include<cstdio>
#include<cstring>
#include<map>
using namespace std;
int nx[1001000];
const int modd=998244353;
typedef unsigned long long ull;
map<ull,int> ma;
void getnx(unsigned int s1[],int n)
{
    nx[1]=0;
    for(int i=2,j=1;i<=n+1;)//next[i] 表示最大的x,满足s1[1 : x - 1] 是s1[1 : i - 1] 的后缀。即i失配该把i变成啥
    {
        nx[i]=j;
        while(j&&s1[j]!=s1[i])j=nx[j];
        j++,i++;
    }
}
char ss[1001000];
const int NN=1e5+10;
unsigned int* s[NN];
int lenth[NN];
int cnt[1001000];
const unsigned int jinzhi=31;
int main(){
	int n;scanf("%d\n",&n);
	for(int i=1;i<=n;i++){
		scanf("%s",ss+1);
		int len=strlen(ss+1);
		lenth[i]=len;
		s[i]=new unsigned int[len+2];
		for(int j=1;j<=len;j++){
			s[i][j]=ss[j]-'a'+1;
		}
		ull pow=1;
		ull ha=0;
		for(int j=len;j>=1;j--){
			ha=pow*s[i][j]+ha;
			pow*=jinzhi;
			ma[ha]+=1;
		}
	}
	long long ans=0;
	for(int i=1;i<=n;i++){
		int len=lenth[i];
		getnx(s[i],len);
		for(int j=1;j<=len;j++){//这里nxi变成1到i的最长公共前后缀长度。
			nx[j]=nx[j+1]-1;
		}
		ull ha=0;
		for(int j=1;j<=len;j++){
			ha=ha*jinzhi+s[i][j];
			cnt[j]=ma[ha];
		}
		for(int j=1;j<=len;j++){
			cnt[nx[j]]-=cnt[j];
		}
		for(int j=1;j<=len;j++){
			ans+=1ll*cnt[j]*j*j%modd;
			ans=ans%modd;
		}
	}
	printf("%lld\n",ans);
	return 0;
}

B.Boundary

题意

有一堆点。找到压到点最多的一定经过原点圆压住了多少点。

题解

这个思路绕个弯。直接枚举两点。反正过原点,三点确定圆。完了开个map啥的记录一下圆,往圆上加点就完了。或者统计同一个圆出现了几次。一个圆出现的次数应该是其上的点的不同点对数,即 n u m = n ( n − 1 ) / 2 num=n(n-1)/2 num=n(n1)/2统计出num选最大值枚举n就行。然而我代码老wa,也不知道咋肥四。。。有会的大佬帮忙康康。

没AC代码

#include<cstdio>
#include<cstring>
#include<set>
#include<map>
#include<cstring>
#include<algorithm>
#include<cstdlib>
using namespace std;
const int NN=1e4+10;
struct Circle
{
	double x,y;
	Circle(double a=0,double b=0):x(a),y(b){}
	void print(){
		printf("%lf %lf\n",x,y);
	}
}circ[2000010];
const double eps=0.00000001;
bool cmp_xy(Circle const &a,Circle const &b){
    if(a.x<b.x)return 1;
    else if(a.x==b.x&&a.y<b.y)return 1;
    return 0;
}

//map<Circle,set<int>,cmp_xy> ma; 
double x[NN],y[NN];
int getres(long long kk){
	int i;
	for(i=2;1ll*i*(i-1)<kk;i++);
	return i;
}
double abss(double x){
	if(x<0)return -x;
	else return x;
}
int main(){
	int n;scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%lf%lf",x+i,y+i);
	}
	int ans=0;
	int cnt=0;
	for(int i=1;i<=n;i++){
		for(int j=i+1;j<=n;j++){
			if((x[i]==0&&x[j]==0)||y[i]/x[i]==y[j]/x[j]){
				continue;
			}
			double k1,b1,k2,b2,xx,yy;
			if(y[i]==0){
				k2=-x[j]/y[j];
				b2=y[j]/2+x[j]*x[j]/2/y[i];
				xx=x[i]/2;
				yy=k2*xx+b2;
			}
			else if(y[j]==0){
				k1=-x[i]/y[i];
				b1=y[i]/2+x[i]*x[i]/2/y[i];
				xx=x[j]/2;
				yy=k1*xx+b1;
			}
			else{
				k1=-x[i]/y[i];
				b1=y[i]/2+x[i]*x[i]/2/y[i];
				k2=-x[j]/y[j];
				b2=y[j]/2+x[j]*x[j]/2/y[i];
				xx=(b2-b1)/(k1-k2);
				yy=k1*xx+b1;
			}
			circ[++cnt]=Circle(xx,yy);
			// neww.print();
			// for(set<int>::iterator k=ma[neww].begin();k!=ma[neww].end();++k){
			// 	printf("%d",*k);
			// }printf("\n");
		}
	}
	sort(circ+1,circ+cnt+1,cmp_xy);
	int num;
	for(int i=1;i<=cnt;i++){
		if(i>1&&abss(circ[i].x-circ[i-1].x)<=eps&&abss(circ[i].y-circ[i-1].y)<=eps)num++;
		else num=1;
		ans=max(ans,num);
	}
	printf("%d\n",getres(1ll*ans*2));
	return 0;
}

自闭了。

CD两题很水,不想写了

E.Exclusive OR

题意

给一个n长度序列,求出选出可重复的i个数的最大异或和。

吐槽

woc这题fwt数组要开long long。我没开wa到跳楼。比如所有2e5个数都是0,那异或卷积完就爆int了。要把每次卷积完的非零项统一成1,否则long long也爆。

题解

这个题关键是对秩的理解。数异或的秩和向量组的秩挺像的。构造线性基的方法其实本质是高斯消元。
注意秩的理解。每组数的异或秩的大小是这组数中线性无关数的最大个数。但是直接找出不好找,要用一直异或的办法找到线性基。这个题不需要构造线性基。秩是19,所以最多19个数一定能选出所有值。所以FWT跑19次。还有就是i次的答案一定不会小于i-2次的答案。所以大于19的次数就是离他最近的(最大的),和它差2的整数倍次数的答案。

AC代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int N;
const int NN=2e5+10;
const int MM=(1<<19)+10;
long long a[MM],b[MM];
void FWT_or(long long *a,int opt)
{
    for(int i=1;i<N;i<<=1)
        for(int p=i<<1,j=0;j<N;j+=p)
            for(int k=0;k<i;++k)
                if(opt==1)a[i+j+k]=(a[j+k]+a[i+j+k]);
                else a[i+j+k]=(a[i+j+k]-a[j+k]);
}
void FWT_and(long long *a,int opt)
{
    for(int i=1;i<N;i<<=1)
        for(int p=i<<1,j=0;j<N;j+=p)
            for(int k=0;k<i;++k)
                if(opt==1)a[j+k]=(a[j+k]+a[i+j+k]);
                else a[j+k]=(a[j+k]-a[i+j+k]);
}
void FWT_xor(long long *a,int opt)
{
    for(int i=1;i<N;i<<=1)
        for(int p=i<<1,j=0;j<N;j+=p)
            for(int k=0;k<i;++k)
            {
                long long X=a[j+k],Y=a[i+j+k];
                a[j+k]=(X+Y);a[i+j+k]=(X-Y);
                if(opt==-1)a[j+k]=1ll*a[j+k]/2,a[i+j+k]=1ll*a[i+j+k]/2;
            }
}
int ans[NN];
int main() {
    int n;scanf("%d",&n);
    int maxn=0;
    for(int i=1;i<=n;i++){
        int x;scanf("%d",&x);
        maxn=max(maxn,x);
        b[x]++;
    }
    for(N=1;N<maxn;N<<=1);N<<=1;
    a[0]=1;
    FWT_xor(b,1);
    for(int i=1;i<=19;i++){
        FWT_xor(a,1);
        for(int j=0;j<N;j++)a[j]=a[j]*b[j];
        FWT_xor(a,-1);
        for(int j=0;j<N;j++){
            if(a[j]>0){a[j]=1;ans[i]=j;}
        }
    }
    for(int i=1;i<=n;i++){
        if(i>19){
            if((i-19)%2){
                printf("%d ",ans[18]);
            }
            else{
                printf("%d ",ans[19]);
            }
        }
        else{
            printf("%d ",ans[i]);
        }
    }
    return 0;
}
/*
23
1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536 131072 0 0 0 0 0
*/

G. Greater and Greater

吐槽

我发现多校给的时间空间限制真的玄学。这题开两个二维bitset会mle,开一个就不炸。也不知道为啥。开一个如果按照数据范围也是800m会爆炸的。服了。

AC代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<bitset>
#include<iostream>
using namespace std;
const int NN=150010;
const int MM=40001;
bitset<MM> s[MM];
int a[NN],b[MM],bb[MM];
int num1[NN];
bool cmp_b(int x,int y){
	return b[x]<b[y];
}
int so[MM];
int main(){
	int n,m;scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%d",a+i);
	}
	for(int i=1;i<=m;i++){
		scanf("%d",b+i);
		bb[i]=b[i];
		so[i]=i;
	}
	sort(so+1,so+m+1,cmp_b);
	sort(bb+1,bb+m+1);
	for(int i=1;i<=m;i++){
		bitset <MM> I;
		I[so[i]-1]=1;
		s[i]=s[i-1]|I;
	}
	for(int i=1;i<=n;i++){
		num1[i]=upper_bound(bb+1,bb+m+1,a[i])-bb-1;
	}
	bitset<MM> cur;
	bitset<MM> lastcur;
	bitset<MM> Im;Im[m-1]=1;
	for(int i=0;i<m;i++)lastcur[i]=1;
	int ans=0;
	for(int i=n;i>=1;i--){

		cur=((lastcur>>1)|Im)&s[num1[i]];
		if(i<=n-m+1&&cur[0]==1){
			ans++;
		}
		lastcur=cur;
	}
	printf("%d\n",ans);
	return 0;
}

h.Happy Triangle

题解

这题标答是手动平衡树的。但是这个题离线,直接线段树维护区间最小差值就完了。然而我的代码只跑过了50%的数据就挖了。有大佬帮忙康康评论一下。。。我把每个可能是数都按顺序映射到线段树的基本数组中,删除也安排了唯一的点删除,感觉巨对。想破头也不知道咋就挖了。

没AC代码

#include<cstdio>
#include<cstring>
#include<set>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
multiset<int> se;
const int NN=2e5+10;
int minn[NN<<2];
int left[NN<<2];
int right[NN<<2];
int op[NN],v[NN];
const int oo=1e9+10;
map <int,int>ma;
void up(int cur){
	if(left[cur<<1]==-1)left[cur]=left[cur<<1|1];
	else left[cur]=left[cur<<1];
	if(right[cur<<1|1]==-1)right[cur]=right[cur<<1];
	else right[cur]=right[cur<<1|1];
	minn[cur]=min(minn[cur<<1],minn[cur<<1|1]);
	if(left[cur<<1|1]!=-1&&right[cur<<1]!=-1)minn[cur]=min(minn[cur],left[cur<<1|1]-right[cur<<1]);
}
void inser(int cur,int l,int r,int p,int val){
	if(l==r){
		left[cur]=val;
		right[cur]=val;
		minn[cur]=oo;
		return;
	}
	int mid=(l+r)>>1;
	if(p<=mid)inser(cur<<1,l,mid,p,val);
	else inser(cur<<1|1,mid+1,r,p,val);
	up(cur);
}
void eras(int cur,int l,int r,int p){
	if(l==r){
		left[cur]=-1;
		right[cur]=-1;
		minn[cur]=oo;
		return;
	}
	int mid=(l+r)>>1;
	if(p<=mid)eras(cur<<1,l,mid,p);
	else eras(cur<<1|1,mid+1,r,p);
	up(cur);
}
int ans=oo,lastr=-1;
void get_min(int cur,int l,int r,int x,int y){
	if(x<=l&&r<=y){
		ans=min(ans,minn[cur]);
		if(left[cur]!=-1&&lastr!=-1){
			ans=min(ans,left[cur]-lastr);
		}
		lastr=right[r];
		return;
	}
	int mid=(l+r)>>1;
	if(x<=mid)get_min(cur<<1,l,mid,x,y);
	if(y>mid) get_min(cur<<1|1,mid+1,r,x,y);
}
struct pp{
	int v,id;
	pp(int a=0,int b=0):v(a),id(b){};
} num[NN];
bool cmp_v(pp x,pp y){
	if(x.v<y.v)return 1;
	else if(x.v==y.v&&x.id<y.id)return 1;
	else return 0;
}
int a[NN];
int main(){
	int cnt=0;
	memset(left,-1,sizeof(left));
	memset(right,-1,sizeof(right));
	int n;scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d%d",&op[i],&v[i]);
		if(op[i]==1){num[++cnt].v=v[i];num[cnt].id=i;}
	}
	if(cnt<=1){
		for(int i=1;i<=n;i++)printf("No\n");
		return 0;
	}
	sort(num+1,num+cnt+1,cmp_v);
	for(int i=1;i<=cnt;i++){
		a[num[i].id]=i;
	}
	for(int i=1;i<=n;i++){
		if(op[i]==2){
			pp neww;neww.id=0;neww.v=v[i];
			a[i]=lower_bound(num+1,num+cnt+1,neww,cmp_v)-num+ma[v[i]];
			ma[v[i]]=ma[v[i]]+1;
		}
		else if(op[i]==3){
			pp neww;neww.id=0;neww.v=v[i];
			a[i]=lower_bound(num+1,num+cnt+1,neww,cmp_v)-num;
		}
	}
	for(int i=1;i<=(cnt<<2);i++)minn[i]=oo;
	for(int i=1;i<=n;i++){
		if(op[i]==1){
			inser(1,1,cnt,a[i],v[i]);
			se.insert(v[i]);
		}
		else if(op[i]==2){
			eras(1,1,cnt,a[i]);
			se.erase(se.find(v[i]));//直接erase掉vi不对
		}
		else{
			set<int>::iterator pos=se.upper_bound(v[i]);
			int aa=-1,b=-1;
			if(pos!=se.begin()){
				--pos;
				b=*pos;
				if(pos!=se.begin()){
					--pos;
					aa=*pos;
				}
			}
			if(aa!=-1&&b!=-1&&aa+b>v[i]){
				
				printf("Yes\n");
				continue;
			}
			ans=oo;lastr=-1;
			get_min(1,1,cnt,max(1,a[i]-1),cnt);
			if(ans<v[i]){
				printf("Yes\n");
			}
			else{
				printf("No\n");
			}
		}
	}
	return 0;
}
/*
13
3 1
3 2
3 3
1 4
1 4
1 5
2 4
2 4
3 2
3 1
1 4
3 2
3 1
*/

吐槽

卧槽上面那个代码手误了。线段树查询right[cur]写成right[r]了。就这居然能跑过50%的数据。服了。想了好几天,茶饭不思的。还以为有情况没考虑到。。。

AC代码

#include<cstdio>
#include<cstring>
#include<set>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
multiset<long long> se;
const long long NN=400100;
long long minn[NN<<2];
long long left[NN<<2];
long long right[NN<<2];
long long op[NN],v[NN];
const long long oo=2e9+10;
map <long long,long long>ma;
void up(long long cur){
	if(left[cur<<1]==-1)left[cur]=left[cur<<1|1];
	else left[cur]=left[cur<<1];
	if(right[cur<<1|1]==-1)right[cur]=right[cur<<1];
	else right[cur]=right[cur<<1|1];
	minn[cur]=min(minn[cur<<1],minn[cur<<1|1]);
	if(left[cur<<1|1]!=-1&&right[cur<<1]!=-1)minn[cur]=min(minn[cur],left[cur<<1|1]-right[cur<<1]);
}
void inser(long long cur,long long l,long long r,long long p,long long val){
	if(l==r){
		left[cur]=val;
		right[cur]=val;
		minn[cur]=oo;
		return;
	}
	long long mid=(l+r)>>1;
	if(p<=mid)inser(cur<<1,l,mid,p,val);
	else inser(cur<<1|1,mid+1,r,p,val);
	up(cur);
}
void eras(long long cur,long long l,long long r,long long p){
	if(l==r){
		left[cur]=-1;
		right[cur]=-1;
		minn[cur]=oo;
		return;
	}
	long long mid=(l+r)>>1;
	if(p<=mid)eras(cur<<1,l,mid,p);
	else eras(cur<<1|1,mid+1,r,p);
	up(cur);
}
long long ans=oo,lastr=-1;
void get_min(long long cur,long long l,long long r,long long x,long long y){
	if(x<=l&&r<=y){
		ans=min(ans,minn[cur]);
		if(left[cur]!=-1&&lastr!=-1){
			ans=min(ans,left[cur]-lastr);
		}
		lastr=right[cur];
		return;
	}
	long long mid=(l+r)>>1;
	if(x<=mid)get_min(cur<<1,l,mid,x,y);
	if(y>mid) get_min(cur<<1|1,mid+1,r,x,y);
}
struct pp{
	long long v,id;
	pp(long long a=0,long long b=0):v(a),id(b){};
} num[NN];
bool cmp_v(pp x,pp y){
	if(x.v<y.v)return 1;
	else if(x.v==y.v&&x.id<y.id)return 1;
	else return 0;
}
long long a[NN];
int main(){
	long long cnt=0;
	memset(left,-1,sizeof(left));
	memset(right,-1,sizeof(right));
	long long n;scanf("%lld",&n);
	for(long long i=1;i<=n;i++){
		scanf("%lld%lld",&op[i],&v[i]);
		if(op[i]==1){num[++cnt].v=v[i];num[cnt].id=i;}
	}
	if(cnt<1){
		for(long long i=1;i<=n;i++)printf("No\n");
		return 0;
	}
	sort(num+1,num+cnt+1,cmp_v);
	for(long long i=1;i<=cnt;i++){
		a[num[i].id]=i;
	}
	for(long long i=1;i<=n;i++){
		if(op[i]==2){
			pp neww;neww.id=0;neww.v=v[i];
			a[i]=lower_bound(num+1,num+cnt+1,neww,cmp_v)-num+ma[v[i]];
			ma[v[i]]=ma[v[i]]+1;
		}
		else if(op[i]==3){
			pp neww;neww.id=0;neww.v=v[i];
			a[i]=lower_bound(num+1,num+cnt+1,neww,cmp_v)-num;
		}
	}
	for(long long i=1;i<=(cnt<<2);i++)minn[i]=oo;
	for(long long i=1;i<=n;i++){
		if(op[i]==1){
			inser(1,1,cnt,a[i],v[i]);
			se.insert(v[i]);
		}
		else if(op[i]==2){
			eras(1,1,cnt,a[i]);
			se.erase(se.lower_bound(v[i]));//直接erase掉vi不对
		}
		else{
			set<long long>::iterator pos=se.upper_bound(v[i]);
			long long aa=-1,b=-1;
			if(pos!=se.begin()){
				--pos;
				b=*pos;
				if(pos!=se.begin()){
					--pos;
					aa=*pos;
				}
			}
			if(aa!=-1&&b!=-1&&aa+b>v[i]){
				
				printf("Yes\n");
				continue;
			}
			ans=oo;lastr=-1;
			get_min(1,1,cnt,max(1ll,a[i]-1),cnt);
			if(ans<v[i]){
				printf("Yes\n");
			}
			else{
				printf("No\n");
			}
		}
	}
	return 0;
}
/*
13
3 1
3 2
3 3
1 4
1 4
1 5
2 4
2 4
3 2
3 1
1 4
3 2
3 1
*/

I.Interval

这个题是个网格最小割。把区间弄成点,没有花钱限制的流量无穷,限制的流量是价格。完了源点是区间(1,n),汇点新建,所有大小为1的区间往汇点连正无穷的边。跑最小割。然而我的代码跑过了65%的数据就wa了。不知道为啥。。有大佬帮忙康康评论一下。。。。

没AC代码

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
   
using namespace std;
long long oo=2e9+10;
long long read(){
    long long x = 0; long long zf = 1; char ch = ' ';
    while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
    if (ch == '-') zf = -1, ch = getchar();
    while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); return x * zf;
}
  
const int NN=510;
const int MM=NN*NN;
const int VV=NN*NN;
struct Edge{
    int to;
    long long dis;
} edges[MM<<2];
 vector <int> con[VV];
 int cur[VV];
int edge_num=-1;
int n, m, s, t;
   
void addEdge2(int from, int to, long long dis){
    edges[++edge_num].to = to;
    edges[edge_num].dis = dis;
    con[from].push_back(edge_num);
}
   
void addEdge(int from, int to, long long dis){
    addEdge2(from, to, dis), addEdge2(to, from, 0);
}
   
int d[VV];
   
long long DFS(int u, long long flow){
    if (u == t) return flow;
    long long _flow = 0, __flow;
    int up=con[u].size();
    for (int i = cur[u]; i<up ; i++){
        int c_e=con[u][i];
        int v = edges[c_e].to;
        if (d[v] == d[u] + 1 && edges[c_e].dis > 0){
            __flow = DFS(v, min(flow, edges[c_e].dis));
            flow -= __flow;
            edges[c_e].dis -= __flow;
            _flow += __flow;
            edges[c_e^1].dis += __flow;
            if (!flow)
                break;
        }
    }
    if (!_flow) d[u] = -1;
    return _flow;
}
   
bool BFS(){
    memset(d, -1, sizeof(d));
    queue<int> que; que.push(s);
    d[s] = 0; int u, _new;
    while (!que.empty()){
        u = que.front(), que.pop();
        int up=con[u].size();
        for (int i = 0; i<up; i++){
            int c_e=con[u][i];
            _new = edges[c_e].to;
            if (d[_new] == -1 && edges[c_e].dis > 0){
                d[_new] = d[u] + 1;
                que.push(_new);
            }
        }
    }
    return (d[t] != -1);
}
   
long long dinic(){
    long long max_flow = 0;
    while (BFS()){
        for (int i = 1; i <= n; ++i) cur[i] = 0;
        max_flow += DFS(s, oo);
        if(max_flow>=oo)return max_flow;
    }
    return max_flow;
}
int c[NN][NN][2];
int id[NN][NN];
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    memset(c,-1,sizeof(c));
    long long maxn=0;
    for(int i=1;i<=m;i++){
        int x,y,co;
        char op[1];
        scanf("%d%d%s%d",&x,&y,op,&co);
        maxn+=co;
        if(op[0]=='L')c[x][y][0]=co;
        else c[x][y][1]=co;
    }
    oo=maxn+1;
    int v=0;
    for(int i=1;i<=n;i++){
        for(int j=i;j<=n;j++){
            id[i][j]=++v;
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=i+1;j<=n;j++){
            if(c[i][j][0]!=-1){
                addEdge(id[i][j],id[i+1][j],c[i][j][0]);
            }
            else addEdge(id[i][j],id[i+1][j],oo);
            if(c[i][j][1]!=-1){
                addEdge(id[i][j],id[i][j-1],c[i][j][1]);
            }
            else addEdge(id[i][j],id[i][j-1],oo);
        }
    }
    s=id[1][n];t=v+1;
    for(int i=1;i<=n;i++){addEdge(id[i][i],t,oo);}
    long long ans=dinic();
    if(ans>=oo){
        printf("-1\n");
    }
    else printf("%lld\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值