问题 A: 毛毛虫
题目描述
对于一棵树,我们可以将某条链和与该链相连的边抽出来,看上去就象成一个毛毛虫,点数越多,毛毛虫就越大。例如下图左边的树(图 1 )抽出一部分就变成了右边的一个毛毛虫了(图 2 )。
输入
在文本文件 worm.in 中第一行两个整数 N , M ,分别表示树中结点个数和树的边数。
接下来 M 行,每行两个整数 a, b 表示点 a 和点 b 有边连接( a, b ≤ N )。你可以假定没有一对相同的 (a, b) 会出现一次以上。
输出
在文本文件 worm.out 中写入一个整数 , 表示最大的毛毛虫的大小。
样例输入
样例输出
提示
40% 的数据, N ≤ 50000
100% 的数据, N ≤ 300000
问题 B: 十字绣
题目描述
考古学家发现了一块布,布上做有针线活,叫做“十字绣”,即交替地在布的两面穿线。布是一个n*m的网格,线只能在网格的顶点处才能从布的一面穿到另一面。每一段线都覆盖一个单位网格的两条对角线之一,而在绣的过程中,一针中连续的两段线必须分处布的两面。给出布两面的图案,问最少需要几针才能绣出来?一针是指针不离开布的一次绣花过程。
输入
接下来N行每行M个数描述正面。
再接下来N行每行M个数描述反面。
每个格子用.(表示空),/(表示从右上角连到左下角),\(表示从左上角连到右下角)和X(表示连两条对角线)表示。
输出
样例输入
样例输出
提示
问题 C: 卡农
题目描述
今天我们最熟悉 的卡农作 品是 帕赫贝 尔的《D大调卡农》 ,也称作《帕赫贝尔的卡农》。其曲谱例子如图(1)所示 。
Figure 1: 帕赫贝尔的卡农。在曲谱中,第一行(Violin 1)是导句,我们称它为首声部;第二行(Violin 2)是答句,我们称它为二声部;第三行(Violin 3)是另一个答句,我们称它为三声部 。三把小提琴形成三个声部间隔八拍先后加入。小提琴全部拉奏完全相同旋律,音乐悦耳动听。
柳德米拉也想谱一曲优美的卡农,在聚会的时候不停地演奏。她写了一个旋律,然后尝试把它变成卡农。柳德米拉写的曲子很简单,都是由四分音符构成的(这样每个音的持续的时间都一样,另外一个四分音符的音长就是一拍)。由于她不会转调等比较复杂的技法,她就希望她的音乐的导句和若干答句一模一样,都是她谱写的旋律的不断重复,只不过每个答句形成的声部比前一个进入的声部 (导句或答句)晚若干拍开始。当然,每个答句都要在导句奏完第一遍旋律之前开始。
柳德米拉发现,虽然她写的旋律很动听,但是将它随意变成一个卡农后,就不是很优美了。她苦思冥想,觉得是这样一个因素作怪 。
如果某个时刻,有两个及以上的音在响,有些音的组合很和谐,而有些就不和谐。柳德米拉发现,如果两个声部,在相同时刻演奏的音高的差,全都是a的倍数,或者全都是b的倍数,那么它们就是优美组合。
进一步的研究表明,多个声部一起演奏不会显得难听,当且仅当任何两个声部 ,它们都是优美组合。柳德米拉做了一些实验,得到了神奇的数字a和b。现在就请你为她得出她的卡农吧!
输入
输出
样例输入
样例输出
提示
【样例解释】
在第一组数据中,第一个答句在导句演奏完1拍后开始,第二个答句在导句演奏完2拍后开始。可以发现,对于任意两个声部,它们同时演奏的时候,音高差都是1的倍数。又因为每个答句都要在导句奏完第一遍旋律之前开始,所以3就是最大值。
谱出的曲子表示如下:
首声部 (导句): 1 2 3 1 2 3. . .
二声部 (答句): 1 2 3 1 2 3. . .
三声部 (答句): 1 2 3 1 2 3. . .
【数据范围及约定】
对于20%的数据,n<=16
对于40%的数据,n<=100
对于60%的数据,n<=1000
对于80%的数据,n<=10^5
有50%的数据,a=b
对于100%的数据,1<=n<=10^6,1<=a,b<=10^9,0<=h[i]<=10^9,0<=t<=3
问题 D: 最小圈
题目描述
考虑带圈的有向图G=(V,E)以及w:E→R,每条边e=(i,j)(i<>j,i∈V)的权值定义为w[i,j],令n=|V|。C=(c1,c2,…,ck)(ci∈V)是G中的一个圈当且仅当(c[i],c[i+1])(1<=i<k)和(c[k],c[1])都在E中,这是称k为圈c的长度同时令c[k+1]=c[1],并定义圈c=(c1,c2,…,ck)的平均值为,即c上所有边的权值的平均值。令
为G中所有圈c的平均值的最小值。现在的目标是:在给定了一个图G=(V,E)以及w:E→R之后,请求出G中所有圈c的平均值的最小值
输入
输出

样例输入
样例输出
提示
【样例说明】
样例1中共有2个圈(1,2,3)和(1,2,4)。其中第一个圈的平均值为5,第二个圈的平均值为11/3。样例2中存在一个负圈。
【数据范围及约定】
20%的数据:n<=100,m<=1000;
50%的数据:n<=1000,m<=5000;
100%的数据:n<=3000,m<=10000;
100%的数据:|w[i,j]|<=10^7。
T1 毛毛虫 worm
DFS
首先要搞清楚毛毛虫的定义是啥,我考试的时候愣是没想清楚
毛毛虫就是一条链加上这个链上的点直接连的边
dfs处理出与每一个点相连的最长和次长的链来,
之后加上每个点相连的总边数-1即可(去掉自己)
T2 十字绣
DFS+建图
详细的简图题解见波哥给的题解,因为我也是说不明白。
将正图和反图套在一起,之后两边分别建图,dfs即可,最后总针数针+反-再/2
T3 卡农
KMP
需要转化求最小循环节就行
详见波哥题解
T4 最小圈
spfa + 二分答案判定
我就大致设定一个最小的平均值,之后重新建图权值为w[i][j]-mid
Spfa判断是否有负环,有的话减小mid
T1
# include <cstdio>
# include <cstring>
# include <vector>
const int MAXN (300010);
int n,m,tot,ans = 0;
int f[MAXN];
int du[MAXN];
int h[MAXN];
bool vis[MAXN];
struct Edge {
int u,v,next;
} e[MAXN << 1];
void add(int u,int v) {
e[++tot].u = u;
e[tot].v = v;
e[tot].next = h[u];
h[u] = tot;
}
void dfs(int x) {
vis[x] = 1;
if(du[x] == 1) {
f[x] = 1;
return ;
}
int mx1 = 0,mx2 = 0,cs = 0;
for(int i = h[x];i;i = e[i].next) {
if(!vis[e[i].v]) {
dfs(e[i].v);
cs++;
if(f[e[i].v] > mx1) {
mx2 = mx1;
mx1 = f[e[i].v];
}
else if(f[e[i].v] > mx2) mx2 = f[e[i].v];
}
}
if(ans < mx1 + mx2 + du[x] - 1) ans = mx1 + mx2 + du[x] - 1;
f[x] = mx1 + cs;
}
void init() {
int u,v,k;
scanf("%d%d",&n,&m);
for(int i = 1; i <= m; ++i) {
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
du[u]++;
du[v]++;
}
for(int i = 1;i <= n;++i) if(du[i] != 1) {
k = i;
break;
}
dfs(k);
printf("%d",ans);
}
int main() {
freopen("worma.in","r",stdin);
freopen("worma.ans","w",stdout);
init();
}
T2
# include <cstdio>
# include <cstring>
# include <climits>
using namespace std;
const int MAXN(50005);
int n,m,ans,tot,cs,pos;
char map[205][205];
int w[205][205],h[MAXN],f[MAXN],z[MAXN];
bool zx[MAXN],vis[MAXN];
struct Edge {
int v,next,w;
} e[MAXN << 3];
int ABS(int x) {
return x < 0 ? -x : x;
}
void add(int u,int v,int w) {zx[u] = zx[v] = 1;if(w == 1) z[u]++;else f[u]++;e[++tot].v = v;e[tot].next = h[u];h[u] = tot;return ;}
void init() {
scanf("%d%d",&n,&m);n++;m++;
for(int i(1); i <= n; ++i) for(int j(1); j <= m; ++j) w[i][j] = ++cs;
for(int i(1); i < n; ++i) {
scanf("%s",map[i] + 1);
for(int j(1); j < m; ++j) {
if(map[i][j] == (char)92) {
add(w[i][j],w[i + 1][j + 1],1);add(w[i + 1][j + 1],w[i][j],1);
} else if(map[i][j] == '/') {
add(w[i + 1][j],w[i][j + 1],1);add(w[i][j + 1],w[i + 1][j],1);
} else if(map[i][j] == 'X') {
add(w[i + 1][j],w[i][j + 1],1);add(w[i][j + 1],w[i + 1][j],1);
add(w[i][j],w[i + 1][j + 1],1);add(w[i + 1][j + 1],w[i][j],1);
}
}
}
for(int i(1); i < n; ++i) {
scanf("%s",map[i] + 1);
for(int j(1); j < m; ++j) {
if(map[i][j] == (char)92) {
add(w[i][j],w[i + 1][j + 1],0);add(w[i + 1][j + 1],w[i][j],0);
} else if(map[i][j] == '/') {
add(w[i + 1][j],w[i][j + 1],0);add(w[i][j + 1],w[i + 1][j],0);
} else if(map[i][j] == 'X') {
add(w[i + 1][j],w[i][j + 1],0);add(w[i][j + 1],w[i + 1][j],0);
add(w[i][j],w[i + 1][j + 1],0);add(w[i + 1][j + 1],w[i][j],0);
}
}
}
}
void dfs(int x) {
vis[x] = 1;pos += ABS(z[x] - f[x]);
for(int i = h[x];i;i = e[i].next) {if(vis[e[i].v]) continue;dfs(e[i].v);}
}
void make(){
for(int i(1);i <= cs;++i) {
if(!vis[i] && zx[i]) {
pos = 0;dfs(i);
if(!pos) ans+=2;
else ans += pos;
}
}
printf("%d",ans / 2);
}
int main() {
freopen("stitch.in","r",stdin);
freopen("stitch.out","w",stdout);
init();
make();
return 0;
}
T3
# include <cstdio>
# include <cstring>
# include <string>
using namespace std;
const int MAXN = 1000010;
int T;
int a,b,n;
int song[MAXN];
int nxt[MAXN];
int temp[MAXN];
int getnxt(int x) {
memset(nxt,0,sizeof(nxt));
for(int i = 0; i < n; ++i) temp[i] = song[i];
for(int i = 0; i < n; ++i) temp[i] %= x;
nxt[0] = 0;
for(int i = 1; i <n; ++i) {
int k = nxt[i];
while(k && temp[k ] != temp[i]) k = nxt[k];
if(temp[k ] == temp[i]) nxt[i+1] = k + 1;
}
/*for(int i = 1;i <= n;++i) printf("%d ",nxt[i]);
printf("\n"); */
return n - nxt[n];
}
void init() {
scanf("%d%d%d",&n,&a,&b);
for(int i = 0; i < n; ++i) scanf("%d",&song[i]);
if(a == b) {
int ans1 = getnxt(a);
if(n % ans1 == 0 && ans1 != n) {
printf("%d\n",n / ans1);
} else {
printf("0\n");
}
} else {
int ans1 = getnxt(a);
int ans2 = getnxt(b);
if(n % ans1 == 0 && n != ans1) {
ans1 = n / ans1;
}
else {
ans1 = 0;
}
if(n % ans2 == 0 && n != ans2) {
ans2 = n / ans2;
}
else {
ans2 = 0;
}
if(ans1 > ans2) {
printf("%d\n",ans1);
}
else {
printf("%d\n",ans2);
}
}
}
void clr() {
memset(song,0,sizeof(song));
memset(nxt,0,sizeof(nxt));
}
int main() {
freopen("canon.in","r",stdin);
freopen("canon.out","w",stdout);
scanf("%d",&T);
while(T--) {
init();
clr();
}
}
T4
# include <cstdio> # include <cstring> using namespace std; const int MAXN(3010); const int MAXM(10010); const double eps(1e-9); bool flag; bool mark[MAXN]; int n,m,tot; int h[MAXM]; int u[MAXM]; int v[MAXM]; double w[MAXM]; double dis[MAXM]; double l,r,mid; struct Edge { int u,v,next; double w; } e[MAXM << 1]; void add(int u,int v,double w) { e[++tot].u = u; e[tot].v = v; e[tot].w = w; e[tot].next = h[u]; h[u] = tot; return ; } void init() { scanf("%d%d",&n,&m); for(int i = 1; i <= m; ++i) scanf("%d%d%lf",&u[i],&v[i],&w[i]),r += w[i]; return ; } void dfs(int x) { mark[x] = 1; for(int i = h[x]; i; i = e[i].next) { if(dis[e[i].v] > dis[x] + e[i].w) { if(mark[e[i].v]) { flag = 1; break; } else { dis[e[i].v] = dis[x] + e[i].w; dfs(e[i].v); } } } mark[x] = 0; } bool check(double x) { for(int i = 1; i <= n; ++i) { dfs(i); if(flag) return 1; } return 0; } void build(double x) { memset(h,0,sizeof(h)); tot = 0; for(int i = 1; i <= m; ++i) add(u[i],v[i],w[i] - x); } void clr() { build(mid); flag = 0; for(int i = 0; i <= n; ++i) dis[i] = 0.0; return ; } void divide() { while(r - l >= eps) { mid = (l + r) / 2.0; clr(); if(check(mid)) r = mid; else l = mid; } printf("%.8lf",l); return ; } int main() { freopen("cycle.in","r",stdin); freopen("cycle.out","w",stdout); init(); divide(); return 0; }