• NOI2013 Day2


    NOI2013 Day2

    矩阵游戏

    题目描述:设矩阵(F)

    (F[n][m](mod (10^9+7)))

    solution:
    这题可以求通项解决。
    (X_i=F[i][m])
    ((a-1)X_1=a^{m-1}((a-1)+b)-b)
    (P=10^9+7)(P)是公认的质数,所以运用费马小定理:
    (a^{P-1} equiv 1 (mod P))
    (m-1=kP+z),则(a^{m-1} equiv a^z(mod P))
    算出右式,然后再用费马小定理处理除法,求出(X_1)
    ((a-1)X_{i+1}=a^{m-1}((cX+d)(a-1)+b)-b)
    化简得:
    ((a-1)X_{i+1}=a^{m-1}(a-1)cX+a^{m-1}((a-1)d+b)-b)
    形如:((a-1)X_{i+1}=AX_i+B)
    求通项。求出(X_n)

    这题也可以用矩阵乘法,将矩阵乘法的二进制变成十进制就好了。

    时间复杂度:(O(n))

    书法家

    题目描述:在一个(n)(m)列的矩阵中,每个格有对应的值,现在矩阵中画('NOI'),下面给出三个书法字的定义:
    1、 (’N’)由若干 ((geq 3)) 个边平行于坐标轴的矩形组成,设由(K)个矩形组成(标号(1 ~ K)),第(i)个矩形的左下角(方格)坐标设为((L_i, B_i)),右上角坐标设为((R_i, T_i)),要求满足:
    a) (L_i leq R_i,B_i leq T_i)
    b) 对任意(1 < i leq K),有(L_i= R_{i−1} + 1)
    c) 对任意(3 leq i < K),有(B_{i-1}− 1 leq T_i leq T_{i−1})(B_i leq B_{i−1})
    d) (B_2 > B_1, T_2 = T_1, B_{K−1} = B_K, T_{K-1} < T_K)
    2、 (’O’)由一个大矩形(A),挖去一个小矩形(B)得到, 这两个矩形的边都平行于坐标轴。 设大矩形 A 左下角的方格坐标为 ((u , v)), 长为(W), 宽为(H) , 则小矩形 B 满足左下角方格坐标为((u + 1, v + 1)), 长 (W − 2),宽(H − 2)。 要
    求满足:
    a) (W ≥ 3, H ≥ 3)
    b) (u > R_K + 1)
    3、 (’I’)(3)个边平行于坐标轴的从下到上的实心矩形组成,从下到上依次标号为(1,2,3),第(i)个矩形的左下角格子坐标设为((P_i, Q_i)),右上角格子坐标设为((G_i, H_i)),要求满足:
    a) (P_i leq G_i, Q_i leq H_i)
    b) (P_1 = P_3 > u + W, G_1 = G_3)
    c) (Q_1 = H_1 = Q_2 − 1, H_2 + 1 = Q_3 = H_3)
    d) (P_1 < P_2 leq G2 < G1)
    (‘NOI')覆盖的格子的值的和的最大值。

    solution
    从左到右dp,(N,O,I)各分成三个阶段,相邻之间有空列,再加两个阶段。(f[i][j][k])表示到第(i)个阶段,上界为(j),下界为(k)的最大值。转移方程有点烦,直接上代码。

    时间复杂度:(O(11mn^2))

    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <algorithm>
    #include <ctime>
    #include <cmath>
    #include <deque>
    #include <queue>
    #include <vector>
    #include <map>
    #include <complex>
    using namespace std;
    
    const int maxn=160;
    const int maxm=510;
    const int oo=int(1e9);
    typedef int arr[maxn][maxm];
    
    int n, m, ans;
    int a[maxn][maxm], sum[maxn][maxm];
    int  f[2][12][maxn][maxn], g[12][maxn][maxn];
    
    void init()
    {
    	scanf("%d%d", &n, &m);
    	for (int i=1; i<=n; ++i)
    		for (int j=1; j<=m; ++j)
    			scanf("%d", &a[i][j]);
    	for (int j=1; j<=m; ++j)
    		for (int i=1; i<=n; ++i)
    			sum[i][j]=sum[i-1][j]+a[i][j];
    }
    void calc_g()
    {
    	for (int i=1; i<=n; ++i)
    		for (int j=n; j>=i; --j)
    			g[1][i][j]=max(g[1][i][j+1], f[0][1][i][j+1]);
    
    	for (int j=1; j<=n; ++j)
    		for (int i=1; i<=j; ++i)
    			g[2][i][j]=max(g[2][i-1][j], f[0][2][i][j]);
    
    	for (int i=1; i<=n; ++i)
    	{
    		g[3][i][i-1]=g[2][i-1][i-1];
    		for (int j=i; j<=n; ++j)
    			g[3][i][j]=max(g[3][i][j-1], g[2][i][j]);
    	}
    
    	for (int j=1; j<=n; ++j)
    		for (int i=j; i>=1; --i)
    			g[4][i][j]=max(g[4][i+1][j], f[0][2][i+1][j]);
    }
    void solve()
    {
    	for (int k=1; k<=11; ++k)
    		for (int i=0; i<=n+1; ++i)
    			for (int j=0; j<=n+1; ++j)
    				f[0][k][i][j]=g[k][i][j]=-oo;
    	ans=-oo;
    	for (int i=1; i<=m; ++i)
    	{
    		calc_g();
    		f[1][4][1][1]=f[0][4][1][1];
    		f[1][8][1][1]=f[0][8][1][1];
    		for (int j=1; j<=n; ++j)
    			for (int k=j; k<=n; ++k)
    			{
    				int tmps=sum[k][i]-sum[j-1][i];
    				int tmpa=a[j][i]+a[k][i];
    
    				//N:
    				f[1][1][j][k]=max(f[0][1][j][k], 0)+tmps;
    				f[1][2][j][k]=max(g[1][j][k], g[3][j][k])+tmps;
    				f[1][3][j][k]=max(g[4][j][k], f[0][3][j][k])+tmps;
    				
    				f[1][4][1][1]=max(f[1][4][1][1], f[0][3][j][k]);
    
    				//O:
    				if (j+1<k)**注意题目**
    				{
    					f[1][5][j][k]=f[0][4][1][1]+tmps;
    					f[1][6][j][k]=max(f[0][5][j][k], f[0][6][j][k])+tmpa;
    					f[1][7][j][k]=f[0][6][j][k]+tmps;
    					f[1][8][1][1]=max(f[1][8][1][1], f[0][7][j][k]);
    				}
    				
    				//I:
    				if (j+1<k)**注意题目**
    				{
    					f[1][9][j][k]=max(f[0][8][1][1], f[0][9][j][k])+tmpa;
    					f[1][10][j][k]=max(f[0][9][j][k], f[0][10][j][k])+tmps;
    					f[1][11][j][k]=max(f[0][10][j][k], f[0][11][j][k])+tmpa;
    					ans=max(ans, f[1][11][j][k]);
    				}
    			}
    		for (int j=1; j<=n; ++j)
    			for (int k=j; k<=n; ++k)
    				for (int p=1; p<=11; ++p)
    				{
    					f[0][p][j][k]=f[1][p][j][k];
    					f[1][p][j][k]=-oo;
    				}
    	}
    }
    int main()
    {
    	freopen("penman.in", "r", stdin);
    	freopen("penman.out", "w", stdout);
    	init();
    	solve();
    	printf("%d
    ", ans);
    	return 0;
    }
    

    快餐店

    题目描述:给出一个只有一个环的连通图,保证环上的点数大于等于(3),求一个点(边上或点)到最远的点最近,求这一距离。

    solution:
    环上的点的子树求直径更新答案,然后求出子树深度作为该点的点权。

    枚举快餐店在那一条边((i)),环上的点分成了离左端点近,和离右端点近,求出离左端点近的,边权加点权最远的点((P_1))右端点亦然((P_2)),求出(W=P_1->P_2(经i的路径边权)+P_1点权+P_2点权),若(W/2),即路径中点在(i)上,则用(W/2)更新答案,否则左端点和右端点更新答案(因为要求快餐店在(i)上)
    至于如何求最远点,按某一时针枚举边,左边和右边的单调性是不变的,因为只是多了一条边和少了一条边,所以可以用单调队列维护。

    时间复杂度:(O(n))

  • 相关阅读:
    前端面试的一道数组元素值去重问题
    数组元素前移,第一个元素放置数组末位
    Linux 查询oracle错误日志&警告日志
    CentOS 6.4 源码安装MySQL 5.6
    Oracle 表空间不足引起的问题及解决方法
    Oracle 强制中止正在执行的SQL语句
    request for member 'GetByteArrayElements'
    jni入门 eclipsecygwin+ndk
    ffmpeg结构体(二)
    ffmpeg结构体(三)
  • 原文地址:https://www.cnblogs.com/GerynOhenz/p/4697338.html
Copyright © 2020-2023  润新知