昨天没写……今天补上吧
一如既往的跪了
棋盘
【问题描述】
给出一个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\n", 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\n",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。
没有然后了……