zoukankan      html  css  js  c++  java
  • 福建省队集训被虐记——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,转载请注明来源
  • 相关阅读:
    HDU 4348 To the moon(可持久化线段树)
    HDU 5875 Function 大连网络赛 线段树
    HDU 5877 2016大连网络赛 Weak Pair(树状数组,线段树,动态开点,启发式合并,可持久化线段树)
    HDU 5876 大连网络赛 Sparse Graph
    HDU 5701 中位数计数 百度之星初赛
    CodeForces 708B Recover the String
    Java实现 蓝桥杯 算法提高 套正方形(暴力)
    ASP.NET生成验证码
    ASP.NET生成验证码
    ASP.NET生成验证码
  • 原文地址:https://www.cnblogs.com/zhber/p/4036049.html
Copyright © 2011-2022 走看看