10-17模拟赛
伪AK。
T3一眼原题太激动把数组开小。
290分,也不错。。。
1.矩形计数
(rect.cpp/c/pas)
【问题描述】
给出圆周上的 N 个点,请你计算出以这些点中的任意四个为四个角,能构成多少个矩
形。
点的坐标是这样描述的,给定一个数组 v[1..N],假设圆心为(0,0),圆的周长 C=∑
v[1..N] ,第一个点坐标为(0,C/(2π))。从第一个点开始,顺时针沿圆周走 v1 个单位长度,
此时坐标为第二个点的坐标,再走 v2 个单位长度,此时为第三个点的坐标,当走完 v1,v2..vi
个距离后,为第 i+1 个点的坐标(全过程都是沿圆周顺时针)。特别的,走完 v1,v2..vn 个
距离后,就会回到第一个点。
【输入】
输入文件名为 rect.in。
输入共 N+1 行。
第一行为正整数 N。
接下来 N 行每行一个正整数。其中第 i+1 行表示的是 v[i]。
【输出】
输出文件名为 rect.out。
输出共 1 行,一个整数,表示能构成的矩形的个数。
想一下圆的性质,直径所对的圆周角是90度。
又因为我们找的是矩形,所以矩形的对角线都是直径。
所以统计直径数目,然后可以直接组合数求,但是数据范围下,我用了稳妥的枚举求。
code:
#include <iostream>
#include <cstdio>
using namespace std;
const int wx=397;
inline int read(){
int sum=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0'; ch=getchar();}
return sum*f;
}
int sum[wx],pos[wx],t[wx],flag[wx][wx],dis[wx][wx];
int n,ans,len;
int main(){
freopen("rect.in","r",stdin);
freopen("rect.out","w",stdout);
n=read();
for(int i=1;i<=n;i++)pos[i]=read(),len+=pos[i];
for(int i=2;i<=n;i++){
sum[i]=sum[i-1]+pos[i-1];
}
if(len&1){printf("0
");return 0;}
len=len/2;
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
int tmp=sum[j]-sum[i];
dis[i][j]=dis[j][i]=tmp;
if(tmp==len){
t[i]=j; t[j]=i;
}
}
}
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
if(t[i]&&t[j]&&!flag[i][j]&&!flag[j][i]&&!flag[t[i]][t[j]]&&!flag[t[j]][t[i]]&&dis[i][j]==dis[t[i]][t[j]]&&t[i]!=j&&t[j]!=i){
ans++;
flag[i][j]=flag[j][i]=flag[t[i]][t[j]]=flag[t[j]][t[i]]=1;
}
}
}
printf("%d
",ans);
fclose(stdin);
fclose(stdout);
return 0;
}
2.祖先
(ancestor.cpp/c/pas)
【问题描述】
任何一种生物的 DNA 都可以表示为一个由小写英文字母组成的非空字符串。科学家发
现,所有的生物都有可能发生变异。所谓变异,就是子代的 DNA 串与父代的 DNA 串有差
异。每次变异,DNA 串中恰好有一个字符会变成两个任意的字符。一共有 n 种可能的变异。
变异 ai->bici 表示字符 ai 有可能变异为两个字符 bici。详细来说,就是删掉一个字符 ai,之
后在原来 ai 的位置处,插入 bi,ci 两个字符(注意字符 bi 必须在 ci 的前面)。每种变异都
有可能发生任意多次。可以发现,每变异一次,DNA 串的长度会加 1。
如果有一种生物 a,他的 DNA 串是 s1,另外存在一种生物 b,他的 DNA 串是 s2。如
果 s2 可以通过若干次变异变为 s1,那么生物 b 就被叫做生物 a 的祖先。
现在,给定一种生物,他的 DNA 串是 s。请找出他的一个祖先,且这个祖先的 DNA 串
尽量短。
【输入】
输入文件 ancestor.in,共 n+2 行。
第一行包含一个非空字符串 s。
第二行含有一个整数 n,表示所有可能的变异。
接下来 n 行,每行描述一种可能的变异,按照 ai->bici 的格式。
s,ai,bi,ci 仅包含小写英文字母。
请注意:一种变异可能出现多次。
【输出】
输出文件名为 ancestor.out。
输出只有一行,一个整数,表示祖先 DNA 串的最短长度。
一眼DP,不过直接暴力DP的话转移很麻烦。
取巧做一下预处理就好了。
毕竟数据范围小随便乱搞。
code:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int wx=77;
inline int read(){
int sum=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0';ch=getchar();}
return sum*f;
}
char c[wx],tmp[wx];
int f[wx][wx],flag1[wx],flag2[wx],flag3[wx];
bool ok[wx][wx][wx];
int n;
int a[wx];
int main(){
freopen("ancestor.in","r",stdin);
freopen("ancestor.out","w",stdout);
scanf("%s",c+1);
n=read();
for(int i=1;i<=n;i++){
scanf("%s",tmp+1);
flag1[i]=tmp[1]-'a'+1;
flag2[i]=tmp[4]-'a'+1;
flag3[i]=tmp[5]-'a'+1;
}
int len=strlen(c+1);
for(int i=1;i<=len;i++)ok[i][i][c[i]-'a'+1]=1;
for(int l=1;l<=len;l++){
for(int i=1;i<=len-l+1;i++){
int j=i+l-1;
for(int k=i+1;k<=j;k++){
for(int zmj=1;zmj<=n;zmj++){
if(ok[i][k-1][flag2[zmj]]&&ok[k][j][flag3[zmj]])ok[i][j][flag1[zmj]]=1;
}
}
}
}
for(int l=1;l<=len;l++){
for(int i=1;i<=len-l+1;i++){
int j=i+l-1;
for(int k=1;k<=26;k++){
if(ok[i][j][k])f[i][j]=1;
}
if(f[i][j]==0){
f[i][j]=0x3f3f3f3f;
for(int k=i+1;k<=j;k++){
f[i][j]=min(f[i][j],f[i][k-1]+f[k][j]);
}
}
}
}
printf("%d
",f[1][len]);
fclose(stdin);
fclose(stdout);
return 0;
}
3.Formula 1
(f1.cpp/c/pas)
【问题描述】
F1,中文全称为一级方程式锦标赛,是最高级的方程式赛车比赛,现在你作为一名选
手参加了一场 F1 的比赛,比较特殊地,本次比赛是在一个 N 个点 M 条边的无向图上举行
的。
起点是 S,终点是 T,每条边长度为 1 公里,赛车每行驶 1 公里耗油 1 个单位,途中共
有 k 个加油站,每经过加油站时,可以把油加满,但你的赛车设计顾问告诉你,油箱容量越
大,赛车跑的就越慢。为了追求最快的速度,在能顺利到达终点,不会中途没油的前提下,
你希望最小化油箱的容量(注意,虽然油箱变小可能导致路径变长,但我们只关心最小化的
油箱)。
【输入】
输入文件 f1.in。
第一行一个正整数 T 表示测试数据组数,每组数据格式如下:
第一行三个整数,N,M,K,表示无向图的点数,边数,加油站数。
第二行 K 个正整数 i1,i2..ik 表示这些点上有加油站(可能重复,保证至少一个加油站在
S 点)。
接下来 M 行,每行两个正整数 Bi,Ei 表示有一条连接(Bi,Ei)的双向边(可能有重边和自
环)。
最后一行两个正整数 S,T 表示起点、终点。
【输出】
输出文件名为 f1.out。
对于每组数据,如果没法到达终点,输出-1,否则输出最小化的油箱容量
这道题机房其他人都是写的二分,两个大佬切掉了,可是我数组开小了只得90。。。
简直是bzoj4242原题,甚至更加简单。
小岛原理建边真的骚啊。
代码不放了,跟水壶几乎一样。