• 6809. 【2020.10.29提高组模拟】不难题


    大意:给你(K)(1)(n)的排列,让你求([L,R])的序列的操作方案数。
    限定条件:每次操作只能取那些序列中的队首,且取出来组成的序列中不存在连续(R-L+1)个连续的相同的数。
    (n,K<=300)

    (Solution)

    这题可想到平面上只能向右向下走,有若干个障碍,从((1,1))走到((n,m))的方案数。
    考虑容斥,设(f[i])表示当前([l,r])区间中取出来的操作中第一次出现连续的(r-l+1)个连续相同数为(i),且考虑(i)的取出顺序而不考虑(i)以后的那些数的取出顺序的方案数。
    (f[i])可以由取(i)以前的数的总方案数减去前面更早出现了连续(r-l+1)个连续相同数的方案数。
    简而言之,若([l,r])区间内存在(j)使得在其中每个序列内(j)的出现位置都比(i)要前,则(f[i])需减去(f[j]*h(j,i))
    其中(h(j,i))表示(j)(i)之间的那些数的取出方案数。
    对于容斥,我们对(i)在新的(第(r)个)序列中的位置从小到大来进行操作,这样可以保证以前的所有(f[j])都是包含新的(第(r)个)序列的第一次出现的连续的(r-l+1)个连续相同的数的方案数。
    这样我们就不会算重或算漏了。
    为了方便,我们在每个序列后面添加一个(n+1),这样对于每个([l,r])区间的答案就应当是(f[n+1]*ny[r-l+1])了(由于答案不需要考虑(n+1)的取出顺序)。
    则最终的答案就是(sum f[n+1])
    上述容斥的时间复杂度为(O(K^2*K*n^2)),显然会(TLE)
    (也可用维护那些组合数来达到(O(K^2*n^2))的效果,但(TLE)在所难免)

    既然没有天时和人和,我们尝试地利(↓):

    既然是说了独立的随机的排列。那对于([L,R])区间中仍能保证一对((j,i))(j)总是在(i)前面的是少之又少,期望是每次个数都(div 2)
    这样我们可以直接存储下来对于每个(x)当前仍符合条件的(y),然后每次操作后改删的删除即可。
    时间复杂度大约为(O(n*K*(n+K)))
    但是,很容易(TLE),第一发(TLE90)了。
    尝试(AC)中。。。代码待更。。。
    (AC)(果然还是(int)(1LL)大法好)

    (Code)

    #include <cstdio>
    #define N 310
    #define mo 1000000007
    #define ll long long
    #define fo(x, a, b) for (int x = (a); x <= (b); x++)
    #define fd(x, a, b) for (int x = (a); x >= (b); x--)
    using namespace std;
    int K, n, a[N][N], b[N][N], hav;
    int qian_[N], qn[N][N], pl[N][N], cnt[N], f[N];
    int value[N], val[N][N], jc[N * N], ny[N * N], ans = 0;
    	
    inline int read() {
    	int x = 0, f = 0; char c = getchar();
    	while (c < '0' || c > '9') f = (c == '-') ? 1 : f, c = getchar();
    	while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    	return f ? -x : x;
    }
    
    int ksm(int x, int y) {
    	int s = 1;
    	while (y) {
    		if (y & 1) s = 1LL * s * x % mo;
    		x = 1LL * x * x % mo, y >>= 1;
    	}
    	return s;
    }
    
    void prepare() {
    	jc[0] = ny[0] = 1;
    	fo(i, 1, 90000) jc[i] = 1LL * jc[i - 1] * i % mo;
    	ny[90000] = ksm(jc[90000], mo - 2);
    	fd(i, 89999, 1) ny[i] = 1LL * ny[i + 1] * (i + 1) % mo;
    }
    
    inline ll C(int x, int y) {return 1LL * jc[y] * ny[x] % mo * ny[y - x] % mo;}
    
    int main()
    {
    	freopen("nothard.in", "r", stdin);
    	freopen("nothard.out", "w", stdout);
    	prepare();
    	K = read(), n = read(); 
    	fo(i, 1, K) {
    		fo(j, 1, n) a[i][j] = read(), pl[i][a[i][j]] = j;
    		a[i][n + 1] = n + 1, pl[i][n + 1] = n + 1;
    	}
    	n++;
    	fo(L, 1, K - 1) {
    		fo(i, 1, n) f[i] = cnt[i] = 0; f[a[L][1]] = 1;
    		fo(i, 1, n) value[a[L][i]] = 1, qian_[a[L][i]] = i - 1;
    		fo(j, 2, n) fo(i, 1, j - 1) {
    			int x = a[L][j]; b[x][++cnt[x]] = a[L][i];
    			qn[x][cnt[x]] = j - i - 1, val[x][cnt[x]] = 1;
    		}
    		fo(R, L + 1, K) {
    			fo(i, 1, n) {
    				int x = a[R][i]; qian_[x] += i - 1;
    				value[x] = 1LL * value[x] * C(i - 1, qian_[x]) % mo;
    				f[x] = value[x];
    			}
    			fo(i, 1, n) {
    				int x = a[R][i];
    				fo(j, 1, cnt[x]) {
    					if (i < pl[R][b[x][j]]) {
    						b[x][j] = b[x][cnt[x]], qn[x][j] = qn[x][cnt[x]];
    						val[x][j] = val[x][cnt[x]], cnt[x]--; j--; continue;
    					}
    //					printf("%d %d
    ", pl[R][b[x][j]], i);
    					int t = i - pl[R][b[x][j]] - 1;
    					val[x][j] = 1LL *val[x][j] * C(t, qn[x][j] + t) % mo; qn[x][j] += t;
    					f[x] = f[x] + mo - 1LL * val[x][j] * f[b[x][j]] % mo;
    					if (f[x] >= mo) f[x] -= mo;
    				}
    				f[x] = 1LL * f[x] * jc[R - L + 1] % mo;
    			}
    //			printf("%d %d: %lld
    ", L, R, f[n]);
    			ans = (ans + 1LL * f[n] * ny[R - L + 1]) % mo;
    		}
    	}
    	printf("%d
    ", ans);
    	return 0;
    }
    
  • 相关阅读:
    k8spod资源的基础管理操作
    k8s名称空间资源
    bzoj5011: [Jx2017]颜色
    bzoj5010: [Fjoi2017]矩阵填数
    bzoj5008: 方师傅的房子
    bzoj5007: TCP协议
    bzoj5003: 与链 5004: 开锁魔法II 5005:乒乓游戏
    bzoj5020: [THUWC 2017]在美妙的数学王国中畅游
    bzoj5006: [THUWC2017 Bipartite]随机二分图
    bzoj4480: [Jsoi2013]快乐的jyy
  • 原文地址:https://www.cnblogs.com/jz929/p/13912909.html
Copyright © 2020-2023  润新知