T1:反射
T2:自动匹配
T3:道路阻塞
T4:密码编码
全是Farmer Jonh与奶牛题,看来出题人很喜欢USACO
农夫约翰把他的很多镜子遗落在房子外面,他的奶牛们对这些镜子很好奇,于是奶牛们把这些镜子偷了!
奶牛们把镜子放在了一个N*M的矩阵中,在每个小方格中,他们将镜子按正对角线或者反对角线的方式放置,也就是说镜子的放置形状要么是’/’,要么是’\’。
某一天晚上,奶牛贝里斯拿着一个手电筒站在矩阵的外面,他打开手电筒按水平或者垂直方向朝矩阵内的镜子照射,由于镜子是对角线或者反对角线放置的,所以如果垂直的光过来的话,反射出来的光就是水平的,反之也是同样的道理。贝里斯想要知道他从外面照过来的光最多能被镜子反射几次。
第一行是两个正整数N和M,表示矩阵的大小。
接下里N行,每行M个字符,表示矩阵内镜子放置的情况。字符是’/’或者’\’。
输出一个整数,表示从外面照射进来的一束光最多能在矩阵内被反射的次数,如果会被反射无限次,就输出-1。
3 3
/\\
\\\
/\/
3
分行、列枚举镜子反射的每种情况,用f表示当前的方向,方向用1.2.3.4代替,然后判断一些不合法。
还有很玄学的一点:不用判断 -1输出。
#include
#include
#include
#include
using namespace std;
char a[1001][1001];
int ans,maxx,n,m;
int f=0,f2=0;
int main()
{
freopen("mirror.in","r",stdin);
freopen("mirror.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>a[i][j];
for(int i=1;i<=n;i+=n-1)
for(int j=1;j<=m;j++)
{
if(i==1) f=1; //方向
else f=3;
ans=0;
int x=i,y=j;
while(i==i) //行
{
f2=f;
if(a[x][y]=='/'&&f==1&&y>=1) y--,f=4; //镜子每种情况,再改变方向
else if(a[x][y]=='/'&&f==2&&x>=1) x--,f=3;
else if(a[x][y]=='/'&&f==3&&y<=m) y++,f=2;
else if(a[x][y]=='/'&&f==4&&x<=n) x++,f=1;
else if(a[x][y]!='/'&&f==1&&y<=m) y++,f=2;
else if(a[x][y]!='/'&&f==2&&x<=n) x++,f=1;
else if(a[x][y]!='/'&&f==3&&y>=1) y--,f=4;
else if(a[x][y]!='/'&&f==4&&x>=1) x--,f=3;
else break;
if(f2!=f) ans++;
else break;
if(x<1||y<1||x>n||y>m) break;
}
if (ans>maxx) maxx=ans;
}
for(int j=1;j<=m;j+=m-1)
for(int i=1;i<=n;i++)
{
if(j==1) f=2;
else f=4;
ans=0;
int x=i,y=j;
while(i==i) //列
{
f2=f;
if(a[x][y]=='/'&&f==1&&y>=1) y--,f=4;
else if(a[x][y]=='/'&&f==2&&x>=1) x--,f=3;
else if(a[x][y]=='/'&&f==3&&y<=m) y++,f=2; //一样的操作
else if(a[x][y]=='/'&&f==4&&x<=n) x++,f=1;
else if(a[x][y]!='/'&&f==1&&y<=m) y++,f=2;
else if(a[x][y]!='/'&&f==2&&x<=n) x++,f=1;
else if(a[x][y]!='/'&&f==3&&y>=1) y--,f=4;
else if(a[x][y]!='/'&&f==4&&x>=1) x--,f=3;
else break;
if(x<1||y<1||x>n||y>m) break;
}
if(ans>maxx) maxx=ans;
}
printf("%d",maxx);
}
奶牛贝里斯最近有了一部新手机,于是他经常发短信。但是他经常打错单词,因为手机屏幕太小而他的爪子太大了((⊙o⊙))。农夫约翰决定帮助贝里斯来开发一个app应用,使得可以从一个不完整的单词猜想整个单词。
App应用是由W个单词组成的,每个单词都是由’a’…’z’组成的,这些单词总的长度不超过1000000。现在,总共有N个不完整的单词,每个单词的度不超过1000。对于第i个不完整的单词S_i,app应用要计算出在单词库中,按字典序排列的第K_i个前缀是S_i的单词。注意,自己也是自己的前缀。
第一行是两个正整数W和N。
接下来W行,每行一个字典库里的单词。
接下里N行,每行一个K_i和其对应的不完整的单词S_i。
输出包括N行,对于第i行,输出在字典库中按字典序排列的满足前缀是S_i的第K_i个单词在原字典库中的位置。如果没有足够的单词,就输出-1。
10 3
dab
ba
ab
daa
aa
aaa
aab
abc
ac
dadba
4 a
2 da
4 da
3
1
-1
这道题就是字符串处理以及快排+二分查找,用stl的二分查找函数:
lower_bound()就可以把代码简化得特别短。
#include
#include
#include
#include
#include
using namespace std;
string z,name[30001];
int w,n,x;
struct node{
string name;
int place; //存奶牛信息
}s[30001];
bool cmp(node x,node y)
{
return x.name<y.name;
}
int main()
{
freopen("auto.in","r",stdin);
freopen("auto.out","w",stdout);
scanf("%d%d\n",&w,&n);
for (int i=1;i<=w;i++)
{
cin>>s[i].name;
s[i].place=i; //记录位置
}
sort(s+1,s+1+w,cmp); //快排
for(int i=1;i<=w;i++) name[i]=s[i].name;
for(int i=1;i<=n;i++)
{
cin>>x>>z;
int u=lower_bound(name+1,name+1+w,z)-name; //stl二分查找函数
//二分查找name数组里z首次出现的下标
u=u+x-1;
if(u>w) {
cout<<"-1";
continue;
}
if(!name[u].find(z,0)) printf("%d\n",s[u].place); //题目要求直接输出位置
else cout<<"-1";
}
return 0;
}
每天早上,约翰都要从他的家里步行去农场,他途中可能要经过其他的一些地方。我们把这些地方和路抽象成一张图,这张图里有N个点,共有M条边(每条边都是双向边),每条边都有一个长度,约翰的家在第1个点,农场在第N个点,两个点之间没有重复的边,并且这个图是一个连通图,每次约翰从家里到农场总会选一条最短的路径走。
但是约翰的奶牛们老是给约翰捣乱,奶牛们计划在其中某条路上放一些干草堆来阻碍约翰的行走,干草堆放在哪条路上,那条边的长度就相当于增加了一倍。现在,奶牛们想要知道如何选择一条边放干草堆,才能使约翰从家里到农场花费的路程增加最多。
第一行是两个正整数N和M。
接下来M行,每行三个整数a,b,c表示点a到点b的距离是c。
输出从家里到农场的最短路径最多会增加的距离。
5 7
2 1 5
1 3 1
3 2 8
3 5 7
3 4 3
2 4 7
4 5 2
2
这道题就是最短路,用spfa即可。
奶牛们会捣乱,也就是把某一条最短路的距离翻倍,所以我们每次求最短路的时候都乘2,取最大值。
全部做完后再把每条最短路除2,也就是还原就可以了。
#include
#include
#include
using namespace std;
int m,n,k,x[25001],y[25001],a[251][251];
int f[1001000],dis[251],v[251],begin,end;
int spfa(){ //spfa,跑最短路
memset(dis,1,sizeof(dis));
memset(v,0,sizeof(v));
dis[1]=0;
v[1]=1;
f[1]=1;
int head=0,tail=1;
while(head<=tail){
head++;
int res=f[head];
for(int i=1;i<=n;i++){
if(a[res][i]!=0&&dis[i]>dis[res]+a[res][i]){
dis[i]=dis[res]+a[res][i];
if(v[i]!=1){
v[i]=1;
tail++;
f[tail]=i;
}
}
}
v[res]=0;
}
return dis[n]; //注意有返回值
}
int main(){
freopen("rblock.in","r",stdin);
freopen("rblock.out","w",stdout);
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>x[i]>>y[i]>>k;
a[x[i]][y[i]]=k; //赋权值
a[y[i]][x[i]]=k;
}
begin=spfa();
for(int i=1;i<=m;i++){
a[x[i]][y[i]]*=2; //每次*2,奶牛捣乱
a[y[i]][x[i]]*=2;
end=max(spfa()-begin,end); //取最大值
a[x[i]][y[i]]/=2; //再还原
a[y[i]][x[i]]/=2;
}
cout<<end;
return 0;
}
农夫约翰最近想发一些秘密的信息,但是他不想让奶牛们知道。这些信息是‘A’到’Z’的字符组成的,长度至少是2。
为了对这些信息进行加密,农夫约翰对这些信息进行了一系列的操作,每次操作,约翰把字符串S去掉从第一个开始连续的若干个字符或者从最后一个字符开始连续若干个字符(至少去掉一个字符,也不能全部去掉),然后把剩余的字符串添加到原来S串的左边或者右边。例如,对于字符串ABC,一次操作可以有8种结果:
AABC
ABABC
BCABC
CABC
ABCA
ABCAB
ABCBC
ABCC
现在给定最后加密好的字符串,约翰想要知道这个字符串可能由多少种方法加密而来,注意,AAA可以由AA通过四种加密操作得来,虽然产生的AAA是一样的,但是加密的过程是不一样的我们就认为是不同的方法。
一个字符串。
输出这个加密的字符串可以由多少种方法加密而来。【答案要mod 2014】
ABABA
8
这道题要用递归,然后还要用到什么dev-c++自带函数:
substr??好像是个复制子字符串的玄学东西??
小朋友你是否有很多问号?
dalao讲解时我直接疑惑,我做出来就马上补博客……