• 福建省队集训被虐记——DAY3


    昨天没写……今天补上吧

    一如既往的跪了




    棋盘

    【问题描述】

    给出一个N*M的方格棋盘,每个格子里有一盏灯和一个开关,开始的时候,所有的灯都是关着的。用(x, y)表示第x行,y列的格子。(x, y)的开关可以改变(x, y)中灯的状态,同时也可以改变满足|x’-x|=2,|y’-y|=1或者|x’-x|=1,|y’-y|=2的格子(x’, y’)的状态。改变状态的意思是,原来开着的灯会被关掉,原来关着的灯会被开起来。注意这边的改变状态是强制改变的。每个格子的开关最多只能按一次,求能使得所有灯都打开的方案数mod123456789的值。

    【输入格式】

    第一行,N,M。

    【输出格式】

    输出一个整数,表示答案。

    【样例输入1】

    2 3

    【样例输出1】

    4

    【样例解释1】

    XX.    .X.    XXX   .XX

    XX.    XXX    .X.   .XX

    其中X代表按这个格子的开关。

    【样例输入2】

    3 3

    【样例输出2】

    1

    【样例解释2】

    全取。

    【数据规模与约定】

    对于30%的数据,N*M<=20。

    对于60%的数据,N*M<=200。

    对于100%的数据,N,M<=150。



    30分是暴力……不用讲

    60分是高斯消元……因为最多只有n*m=150个点,高斯消元150^3可以过

    100分是坑一点的加优化的高斯消元……在原来的基础上加个bitset还是什么的优化再乱搞+常数优化的就A了

    题解上是这样描述正解的:

    对于100%的数据,我们考虑缩减变量规模和方程规模。

    假如我们确定了前2行和第一列的情况:

    ******

    ******

    *x....

    *.....

    我们注意到,x格子的取法唯一。因为我们要满足最左上方那个格子。

    同理,其他的格子的取法也可以如此推出来了。

    现在我们的变量个数变成了N+M级别的。

    那么同理,我们注意到,如果不是倒2行或者倒1列的格子,一定可以被满足。

    所以我们只需要对这边的格子列方程即可。

    现在变量数和方程数都是N+M级别的。高斯消元即可。

    让我这连高斯消元都不会的情何以堪

    // TopCoder Member SRM 494 Div 1 KnightsOut
    
    #include <set>
    #include <map>
    #include <ctime>
    #include <cmath>
    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int Q = 123456789;
    const int u[9][2] = {{1, 2}, {1, -2}, {2, 1}, {2, -1}, {-1, 2}, {-1, -2}, {-2, 1}, {-2, -1}, {0, 0}};
    int N, M;
    
    int calculatePower(int p)
      {
        int res = 1, i;
        for (i = 0; i < p; i ++)
          res = (res * 2) % Q;
        return res;
      }
    
    int main() {
    	freopen("chess.in", "r", stdin);
    	freopen("chess.out", "w", stdout);
    	scanf("%d%d", &N, &M);
        if (N == 1 || M == 1) {
    		puts("1");
    		return 0;
    	}
        
        int i, j, k, d, t1, t2, cnt, tot = 0, loc;
        vector< vector< vector<int> > > eqn(N);
        for (i = 0; i < N; i ++)
          {
            eqn[i].resize(M);
            for (j = 0; j < M; j ++)
              eqn[i][j].assign(2 * M + N - 1, 0);
          }
        for (i = 0; i < M; i ++)
          eqn[0][i][i] = eqn[1][i][M+i] = 1;
        for (i = 2; i < N; i ++) eqn[i][0][2*M+i-2] = 1;
        for (i = 2; i < N; i ++)
          for (j = 1; j < M; j ++)
            {
              eqn[i][j][2*M+N-2] = 1;
              for (d = 0; d < 9; d ++)
                {
                  t1 = i - 2 + u[d][0], t2 = j - 1 + u[d][1];
                  if (0 <= t1 && t1 < N && 0 <= t2 && t2 < M)
                    if (t1 != i || t2 != j)
                      for (k = 0; k < 2 * M + N - 1; k ++)
                        if (eqn[t1][t2][k] == 1) eqn[i][j][k] ^= 1;
                }
            }
        
        vector< vector<int> > mat(2 * M + N - 1);
        for (i = 0; i < 2 * M + N - 1; i ++)
          mat[i].assign(2 * M + N - 1, 0);
        for (i = 0; i < N; i ++)
          for (j = 0; j < M; j ++)
            if (i == N - 2 || i == N - 1 || j == M - 1)
              {
                for (d = 0; d < 9; d ++)
                  {
                    t1 = i + u[d][0], t2 = j + u[d][1];
                    if (0 <= t1 && t1 < N && 0 <= t2 && t2 < M)
                      for (k = 0; k < 2 * M + N - 1; k ++)
                        if (eqn[t1][t2][k] == 1) mat[tot][k] ^= 1;
                  }
                tot ++;
              }
        mat[tot ++][2*M+N-2] = 1;
        vector<int> res(2 * M + N - 1, 1);
        
        for (cnt = tot, i = 0; i < tot; i ++)
          {
            for (loc = 0; loc < tot; loc ++)
              if (mat[i][loc] == 1) break;
            if (loc >= tot)
              {
                if (res[i] == 1) return 0;
                continue;
              }
            for (cnt --, j = i + 1; j < tot; j ++)
              if (mat[j][loc] == 1)
                {
                  res[j] ^= res[i];
                  for (k = 0; k < tot; k ++) mat[j][k] ^= mat[i][k];
                }
          }
        printf("%d
    ", calculatePower(cnt));
        return 0;
      }
    





    游行

    【问题描述】

    每年春季,在某岛屿上都会举行游行活动。

    在这个岛屿上有N个城市,M条连接着城市的有向道路。

    你要安排英雄们的巡游。英雄从城市si出发,经过若干个城市,到城市ti结束,需要特别注意的是,每个英雄的巡游的si可以和ti相同,但是必须至少途径2个城市。

    每次游行你的花费将由3部分构成:

    1.每个英雄游行经过的距离之和,需要特别注意的是,假如一条边被途径了k次,那么它对答案的贡献是k*ci,ci表示这条边的边权。

    2.如果一个英雄的巡游的si不等于ti,那么会额外增加C的费用。因为英雄要打的回到起点。

    3.如果一个城市没有任何一个英雄途经,那么这个城市会很不高兴,需要C费用的补偿。

    你有无数个的英雄。你要合理安排游行方案,使得费用最小。

    由于每年,C值都是不一样的。所以你要回答Q个询问,每个询问都是,当C为当前输入数值的时候的答案。

    【输入格式】

    第一行正整数N,M,Q;

    接下来的M行,每行ai,bi,ci,表示有一条从ai到bi,边权为ci的有向道路。保证不会有自环,但不保证没有重边。

    接下来Q行,每行一个C,表示询问当每次费用为C时的最小答案。

    【输出格式】

    Q行,每行代表一个询问的答案。

    【样例输入】

    6 5 3

    1 3 2

    2 3 2

    3 4 2

    4 5 2

    4 6 2

    1

    5

    10 

    【样例输出】

    6

    21

    32

    【样例说明】

    第一年的时候,C只有1。我们比较懒所以就不安排英雄出游了,需要支付6的费用。

    第二年的时候,我们可以这么安排:

    第一个英雄1->3->4->5,需要付2+2+2=6的费用,同时还要花5费用打的回家。再花5+5的费用来补偿2号城市和6号城市。

    第三年略。

    【数据范围】

    对于20%的数据,N<=3。

    另外40%的数据,Q<=5。

    对于100%的数据,2<=N<=250,1<=M<=30000,1<=Q<=10000。

    1<=ci<=10000,1<=C<=10000。




    这种神题……表示我只会n^3Floyd一下然后就不会做了

    正解是:首先Floyd。对于每一个询问,每个点拆点搞成二分图,左边n个右边n个。然后左右连边。对于两个点i , j连容量为1、费用为dist[i][j]的边。一开始费用直接取n*c,就是什么也不取。然后开始匹配,每次匹配之后都会使ans+=V-C。那么则可以分成合并成一个环、合并成树两种。注意到对于一个询问,C是给定的,V是固定的,所以直接预处理出所有增广路,然后读入c直接输出答案就行了

    #include<cstdio>
    #include<cstring>
    const int N=505,M=130005;
    int n,m,Q,l=1,S,T,x,y,z,a[N][N],d[N],pre[N],f[M*5],c[M];
    int st[M],ed[M],data[M],cost[M],next[M],son[N];
    bool b[N];
    inline int min(int a,int b)
    {return a<b?a:b;}
    void addedge(int x,int y,int z,int c)
    {
    	st[++l]=x; ed[l]=y; data[l]=z; cost[l]=c; next[l]=son[x]; son[x]=l;
    	st[++l]=y; ed[l]=x; data[l]=0; cost[l]=-c; next[l]=son[y]; son[y]=l;
    }
    int spfa()
    {
    	for (int i=S;i<=T;i++) d[i]=100000000,b[i]=0;
    	int h=0,t=1; f[1]=S; d[S]=0;
    	while (h<t){
    		int i=f[++h]; b[i]=0; if (d[i]>=d[T]) continue;
    		for (int p=son[i];p;p=next[p]) if (data[p]){
    			int j=ed[p]; if (d[i]+cost[p]>=d[j]) continue;
    			d[j]=d[i]+cost[p]; pre[j]=p; if (!b[j]) b[j]=1,f[++t]=j;
    			}
    		}
    	for (int p=T;p!=S;p=st[p]) p=pre[p],data[p]--,data[p^1]++;
    	return d[T];
    }
    int main()
    {
    	freopen("parade.in", "r", stdin);
    	freopen("parade.out", "w", stdout);
    	scanf("%d%d%d",&n,&m,&Q);
    	S=0;T=n+n+1;
    	memset(a,6,sizeof(a));
    	for (int i=1;i<=m;i++)
    	  {
    	    scanf("%d%d%d",&x,&y,&z);
    	    a[x][y]=min(a[x][y],z);
    	  }
    	for (int i=1;i<=n;i++)
    	  for (int j=1;j<=n;j++)
    	    for (int k=1;k<=n;k++)
    	      if (a[i][k]+a[k][j]<a[i][j]) a[i][j]=a[i][k]+a[k][j];
    	for (int i=1;i<=n;i++) addedge(S,i,1,0),addedge(i+n,T,1,0);
    	for (int i=1;i<=n;i++)
    	  for (int j=1;j<=n;j++)
    	    addedge(i,j+n,1,a[i][j]);
    	int now=spfa(),cnt=n;
    	for (int i=0;i<=10000;i++){
    		while (now==i) cnt--,now=spfa();
    		c[i+1]=c[i]+cnt;
    		}
    	while (Q--) scanf("%d",&x),printf("%d
    ",c[x]);
    	return 0;
    }



    模板题

    【问题描述】

    给一个N个点M条边的有向图,求边权和尽量大的一条简单路径。

    简单路径的定义是不会经过重点的路径。

    【输入格式】

    第一行是数据编号。

    第一行正整数N,M,表示点数和边数。

    接下来的M行,每行a, b, c,表示从a到b一条边权为c的边。

    【输出格式】

    第一行输出你找到的简单路径的边的个数

    接下来若干行输出你的边的下标。边从1开始标号。

    【样例输入】

    10

    3 3

    1 2 1

    1 3 1

    2 3 1

    【样例输出】

    2

    1 3

    【样例说明】

    1->2,2->3最优。输出边的下标1和3。

    【评分标准】

    每个点有3个评分标准a1,a2,a3。

    如果你的答案>=a1,得10分。

    如果你的答案>=a2,得7分。

    如果你的答案>=a3,得4分。

    如果你的答案>0,得1分。

    取能得到的最高的分。

    测评方式和昨天一样,过一段时间会放出gen.exe,直接提交graph-upload.cpp即可。



    这坑爹啊……首先引用题解对每一个数据点的描述:

    0:2*N的网格图。

    1:n=14,随便暴力。

    2:树。

    3:看起来是一棵树,实际上是一棵树加上一个环套树。

    4:环套树,随机选取生成树很难A掉。

    5:数据规模较小一些的环套树,随机选取多个生成树来做树的情况可以A。

    6:环套树随机加上了一些边权为-3000000的边。

    7: 仙人掌。

    8:DAG。

    9:分层图,一层内是一个环。

    受到昨天黄巨大随机化70分的影响,我写的就是个随机加边+随机起点+随机退出的骗分,只不过多做几次。但是还是各种wa呀wa

    代码太丑没脸见人了……就不贴了

    正解是:

    对于数据0,dp。

    对于数据1,暴力乱搞。

    对于数据2,dp。

    对于数据3,枚举树上节点搞啊搞

    对于数据4,树形dp。

    对于数据5,如题解所说枚举生成树乱搞

    对于数据6,删边完同3。

    对于数据7,不要问我我也不会……关键是我忘了原来黄哥哥说怎么做了

    对于数据8,有向无环图什么的随便拓扑排序之类的乱搞吧

    对于数据9,这可以保存每层环的状态dp。

    没有然后了……

    ——by zhber,转载请注明来源
  • 相关阅读:
    《Python数据挖掘入门与实践》高清中文版PDF+英文版+源码下载
    discuz 论坛配置 QQ/163 网易邮箱
    Discuz! X3 去掉内容图片提示下载方法(去除图片提示下载附件)
    HTTPS的建立过程(SSL建立安全会话的过程)
    前端开发之走进Vue.js
    优雅统计代码耗时的4种方法!
    Maven配置多个远程仓库的实现方法
    idea maven 一直报错“Could not transfer artifact ......(系统找不到指定的路径。)”
    IntelliJ IDEA为类和方法自动添加注释
    maven “mvn clean package”和“mvn clean install”有什么不同?
  • 原文地址:https://www.cnblogs.com/zhber/p/4036049.html
Copyright © 2020-2023  润新知