zoukankan      html  css  js  c++  java
  • 福建省队集训 20180710

    福建省队集训 20180710

    matrix

    感觉直接对偶+费用流吧。

    考虑直接把一行或者一列+1,显然还是满足条件的,至于初始条件直接全0

    然后每个合法状态之间的变换一定可以被表示成每行/列加几次,如果拆出来还有剩的话一定是不合法的。

    那么转化成这个问题:设(p_x)为这一行加了多少次,(h_{x})为这一列加了多少次

    考虑每个格子的数,(p_i+h_{j}geq w_{i,j}),这是lp的约束

    然后考虑最后要求的方案,(operatorname{minimize} n*left(sum_ip_i+sum_ih_i ight))

    这不就是对偶之后的标准形式了吗,所以我猜是对的

    关于对偶:

    [operatorname{minimize} sum_ip_i+sum_ih_i\ operatorname{s.t} left{egin{array}{l}p_i+h_jgeq w_{i,j}\ p_i,h_igeq 0 end{array} ight. ]

    变成

    [egin{array}{c} operatorname{maximize} sum_{(u, v)} w_{u v} d_{u v} \ ext {s.t}left{egin{array}{l} sum_{v} d_{u v} leq 1, u in X \ sum_{v} d_{u v} leq 1, v in Y end{array} ight. end{array} ]

    如果闲的无聊也可以把度数矩阵和w和一排1的矩阵拿来用数学角度考虑...

    然而费用流我不知道怎么输出方案(群里EI和myh说可以直接二分图的最小覆盖,但是我不知道怎么覆盖),还是用KM吧。

    第一次写的时候没保存就关机了,我是SB

    paper

    或许是做完T1看了一眼题解瞟到了啥启发了一下,反正想出来了,看来以后还是全部做完再看题解

    首先考虑行不管怎么折之后都不影响列的匹配,因为折之后相当于把相同的状态缩在了一起。

    那么行和列就是独立的,考虑分别计算能缩成的区间的方案数

    考虑manacher求出列的以当前列为中点的最大回文串长度,那么这个点的状态可以从这个区间里继承,记录一个后缀就能快速判断了。然后对于答案求一个前缀和再枚举右端点。

    #include<bits/stdc++.h>
    #define ll long long
    #define ROF(i,a,b) for(int i=a;i>=b;--i)
    #define FOR(i,a,b) for(int i=a;i<=b;++i)
    using namespace std;
    int read(){
    	int x=0,pos=1;char ch=getchar();
    	for(;!isdigit(ch);ch=getchar()) if(ch=='-') pos=0;
    	for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
    	return pos?x:-x; 
    } 
    const int N = 1002001;
    int n,m;
    vector<int>vec[N],vec2[N];
    char s[N];
    int tp,p[N],pre[N],suf[N],ansp[N],anss[N],top=0;
    int check(int r,int l){
    	if(l<0||r>tp+1) return 0;
    	if(l%2==0) return 1;
    	l=(l)/2,r=(r)/2;
    	FOR(i,1,n){
    		if(vec[i][l]!=vec[i][r]) return 0;
    	}
    	return 1;
    }
    ll manacher1(){
    	tp=2*m-1;
    	int mid=0,mr=0;top=0;
    	pre[0]=pre[1]=1;
    	FOR(i,1,tp){
    		if(i<=mr) p[i]=min(p[(mid<<1)-i],mr-i);
    		for(;check(i+p[i]+1,i-p[i]-1);++p[i]);
    		if(i+p[i]>mr){
    			mr=p[i]+i;
    			mid=i;
    		} 
    		if(i%2==1) continue;
    		int now=i/2;ansp[now+1]=ansp[now];
    		if(pre[now-p[i]/2+1]){
    			ansp[now+1]++;
    			FOR(j,top,now+1) pre[j]=1;
    			top=now; 
    		}
    	}
    //	mid=tp+1;int ml=tp+1;
    	top=m;suf[m]=1;
    	ROF(i,tp,1){
    		if(i%2==1) continue;
    		int now=i/2;//anss[now]=anss[now+1];
    		if(suf[now+p[i]/2]){
    			anss[now]++;
    			ROF(j,top,now) suf[j]=1;
    			top=now; 
    		}
    	}
    	anss[m]=1;
    	ll ans=0;
    	FOR(i,1,m){
    		ans+=(ansp[i]+1)*anss[i];
    	}
    	return ans;
    }
    int check2(int r,int l){
    	if(l<0||r>tp+1) return 0;
    	if(l%2==0) return 1;
    	l=(l)/2,r=(r)/2;
    	FOR(i,1,n){
    		if(vec2[i][l]!=vec2[i][r]) return 0;
    	}
    	return 1;
    }
    ll manacher2(){
    	tp=2*m-1;
    	int mid=0,mr=0;top=0;
    	pre[0]=pre[1]=1;
    	FOR(i,1,tp){
    		if(i<=mr) p[i]=min(p[(mid<<1)-i],mr-i);
    		for(;check2(i+p[i]+1,i-p[i]-1);++p[i]);
    		if(i+p[i]>mr){
    			mr=p[i]+i;
    			mid=i;
    		} 
    		if(i%2==1) continue;
    		int now=i/2;ansp[now+1]=ansp[now];
    		if(pre[now-p[i]/2+1]){
    			ansp[now+1]++;
    			FOR(j,top,now+1) pre[j]=1;
    			top=now; 
    		}
    	}
    //	mid=tp+1;int ml=tp+1;
    	top=m;suf[m]=1;
    	ROF(i,tp,1){
    		if(i%2==1) continue;
    		int now=i/2;//anss[now]=anss[now+1];
    		if(suf[now+p[i]/2]){
    			anss[now]++;
    			ROF(j,top,now) suf[j]=1;
    			top=now; 
    		}
    	}
    	anss[m]=1;
    	ll ans=0;
    	FOR(i,1,m){
    		ans+=(ansp[i]+1)*anss[i];
    	}
    	return ans;
    }
    int main(){
    	freopen("paper.in","r",stdin);
    	freopen("paper.out","w",stdout);
    	n=read(),m=read();
    	FOR(i,1,n){
    		scanf("%s",s);
    		int l=strlen(s);
    		FOR(j,0,l-1){
    			vec[i].push_back(s[j]-'a');
    		}
    	}
    	ll ans=1;
    	ans*=manacher1();
    	FOR(i,1,n){
    		FOR(j,0,vec[i].size()-1){
    			vec2[j+1].push_back(vec[i][j]);
    		}
    	}
    	swap(n,m);
    	memset(pre,0,sizeof pre);
    	memset(suf,0,sizeof suf);
    	memset(ansp,0,sizeof ansp);
    	memset(anss,0,sizeof anss);
    	memset(p,0,sizeof p);tp=top=0;
    	ans*=manacher2();
    	printf("%lld",ans);
    	return 0;
    }
    

    stone

    博弈,完全不会系列。

    首先找到最高的有奇数个 1 的位,显然我们只需要考虑这一位(如果不存在就是平局)。

    那么现在序列中只有 0 和 1,取到奇数个 1 的获胜。

    如果 n 是偶数,那么 Alice 显然可以取到下标为奇数的所有位置或者下标为偶数的所有位置,因此一定获胜。 (总有一个异或和是1)

    如果 n 是奇数,如果 Alice 第一步取 0,那么 Bob 同理可以获胜(上面的情况),因此 Alice 第一步必须取 1。

    如果两端都是 1 我们就枚举一个取走。同理,接下来 Alice 每一步必须和 Bob 上一步取走一样的数。 不难证明 Alice 能做到这一点当且仅当序列满足以下条件:先不断删去头尾相同的数剩下的数必须是(x1=x2,x3=x4,x5=x6,cdots)此时如果1的总个数为4k+1, 那么 Alice 就会取到奇数个 1,就能获胜。

  • 相关阅读:
    z-index优先级小结
    如何消除img间的默认间隙
    text-align和vertical-align
    HTTP
    HTTP
    HTTP
    HTTP
    ES6标准入门
    ES6标准入门
    ES6标准入门
  • 原文地址:https://www.cnblogs.com/lcyfrog/p/13064528.html
Copyright © 2011-2022 走看看