都可以从COGS上找到
纵横字谜(krizaljka)
时间限制: 1 Sec 内存限制: 32 MB
题目描述
给出两个单词,找到第一个相同的字母,然后第一个单词横数输出,第二个竖着输出形成十字形。
如果两个单词有多个位置的字母相同,则先考虑在第一个单词中位置靠前的相同字母。
例如,第一个单词是 “ABBA”,第二个单词是 “CCBB",形成的纵横字谜格式为:
.C..
.C..
ABBA
.B..
输入
第1行:2个空格分开的单词A和B,长度均不超过30个字符。
输出
令A长度为M,B长度为N,则输出共M行,每行N个字符。A单词橫着输出,B单词竖着输出。不是单词字母的位置填充句点'.'
样例输入
REPUBLIKA HRVATSKA
样例输出
H........
REPUBLIKA
V........
A........
T........
S........
K........
A........
Solution
考点:是否会编程
随便枚举,然后随便输出
Code
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; void Freopen() {freopen("krizaljka.in","r",stdin); freopen("krizaljka.out","w",stdout);} void Fclose() {fclose(stdin); fclose(stdout);} char s1[40],s2[40]; char S[40][40]; int main() { Freopen(); scanf("%s",s1+1),scanf("%s",s2+1); int ls1=strlen(s1+1),ls2=strlen(s2+1); int p1=0,p2=0; for (int i=1; i<=ls1; i++) for (int j=1; j<=ls2; j++) if (s2[j]==s1[i] && !p1 && !p2) {p1=i,p2=j;} for (int i=1; i<=ls2; i++) for (int j=1; j<=ls1; j++) S[i][j]='.'; for (int i=1; i<=ls1; i++) S[p2][i]=s1[i]; for (int j=1; j<=ls2; j++) S[j][p1]=s2[j]; for (int i=1; i<=ls2; i++) { for (int j=1; j<=ls1; j++) putchar(S[i][j]); if (i!=ls2) puts(""); } Fclose(); return 0; }
砍树(eko)
时间限制: 1 Sec 内存限制: 32 MB
题目描述
N棵树,每棵都有一个整数高度。有一个木头的总需要量M。
现在确定一个最大的统一的砍树高度H,如果某棵树的高度大于H,则高出的部分被砍下。使得所有被砍下的木材长度之和达到M(允许稍超过M)。
例如,有4棵树,高度分别是20 15 10 17, 需要的木材长度为 7,砍树高度为15时,第1棵树被砍下5,第4棵树被砍下2,得到的总长度为7。如果砍树高度为16时,第1棵树被砍下4,第4棵树被砍下1,则得到的木材数量为5。
输入
第1行:2个整数N和M,N表示树木的数量(1 ≤ N ≤ 1 000 000),M表示需要的木材总长度(1 ≤ M ≤ 2 000 000 000)。
第2行: N个整数表示每棵树的高度,值均不超过1 000 000 000。所有木材高度之和大于M,因此必然有解。
输出
第1行:1个整数,表示砍树的最高高度。
样例输入
5 20
4 42 40 26 46
样例输出
36
Solution
二分+判断 随便写....
Code
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; void Freopen() {freopen("eko.in","r",stdin); freopen("eko.out","w",stdout);} void Fclose() {fclose(stdin); fclose(stdout);} int read() { int x=0,f=1; char ch=getchar(); while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();} while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();} return x*f; } #define MAXN 1000010 int N,M,h[MAXN],maxh; bool check(int x) { long long sum=0; for (int i=1; i<=N; i++) if (h[i]>x) sum+=h[i]-x; return sum>=M; } int main() { Freopen(); N=read(),M=read(); for (int i=1; i<=N; i++) h[i]=read(),maxh=max(maxh,h[i]); int l=1,r=maxh; while (l<=r) { int mid=(l+r)>>1; if (check(mid)) l=mid+1; else r=mid-1; } printf("%d ",l-1); Fclose(); return 0; }
DNA
时间限制: 1 Sec 内存限制: 32 MB
题目描述
给出1个只有A、B组成的长度为N的字符串,现在给出两种变换方式:第一种是翻转一个字母,A变成B,或B变成A;第二种是翻转字符串某个字符的前缀(包括该字符),将前缀中所有的A变成B,或者所有的B变成A。
现在要把给出的字符串变成全A,问至少需要多少次变换操作。
输入
第1行: 一个正整数N(1<=N<=1000000),表示字符串的长度。
第2行: N个字符,要么是A,要么是B,表示初始字符串.
输出
第1行:一个整数,表示最少需要的翻转次数
样例输入
12
AAABBBAAABBB
样例输出
4
Solution
贪心或者DP
从最后一个位置开始从前往后扫,
如果遇见一个单个的'B'则单独修改ans++,如果遇见>=2个‘B'则前缀翻转ans++
翻转随便打个标记
Code
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; void Freopen() {freopen("dna.in","r",stdin); freopen("dna.out","w",stdout);} void Fclose() {fclose(stdin); fclose(stdout);} #define MAXN 1000100 int N,s[MAXN],ans; char S[MAXN]; int main() { Freopen(); scanf("%d",&N); scanf("%s",S+1); for (int i=1; i<=N; i++) if (S[i]=='A') s[i]=1; else s[i]=0; int i=N,f=0; while (i>=1) { if ((f==0 && s[i]==1) || (f==1 && s[i]==0)) {i--; continue;} if ((f==0 && s[i]==0 && s[i-1]!=0) || (f==1 && s[i]==1 && s[i-1]!=1)) {ans++; i--; continue;} if ((f==0 && s[i]==0 && s[i-1]==0) || (f==1 && s[i]==1 && s[i-1]==1)) { int j; for (j=i; j>=1; j--) if ((f==0 && s[i]==0) || (f==1 && s[i]==1)) {ans++; f^=1; i=j; break;} continue; } } printf("%d ",ans); Fclose(); return 0; }
旅行
POD
现在让我们来对一个交通运输图进行研究,这可能是一个公交车的线路网、有轨电车线路网、地下铁的线路网或是其他的一个什么。这个图中的顶点(从1到n标号)为车站,边(pi ,pj)(这里pi ¹ pj)表示在顶点pi和顶点pj间存在一条直接连接两点的路(1 £ pi, pj £ n)。在图中有从1到k编号的k条运输路线,第l号路线是用一个车站序列pl,1, pl,2, …, pl,sl来描述的,它们为使用这个线路的车辆将依次经过的车站。并且我们给出它们之间的距离rl,1, rl,2, …, rl,sl-1,其中rl,i表示从车站pl,i到车站pl,i+1所需的时间。对于一条线路来说,它上面所有的车站都是不相同的(也就是说,若i ¹ j,则pl,i ¹ pl,j)。且线路l将以频率cl运行。这里cl为集合{6, 10, 12, 15, 20, 30 ,60}中的一个数,它表示每个小时的0, cl, 2cl, …, 60分钟的时候在路线l上的将有两辆车同时从车站pl,1和pl,sl出发相对着行进。
在这样一个运输网络中,我们想从其中的一个车站x出发用尽可能少的时间到达车站y。这里我们假设最少的时间不会超过24个小时,且在中途换车的时候的时间不计。
示例:
在下图中你可以看到一个具有六个车站和两条路线的运输网络。路线一上的车站序列为1、3、4、6,路线二上的车站序列为2、4、3、5,且两条路线的频率分别为c1=15和c2=20。车辆在各车站间移动时的耗费都分别用1和2的下标标在了图上。
现在我们假设在23点30分的时候我们在车站5想要到车站6去。我们必须等上10分钟才可以搭上一辆路线2的车离开。然后我们就面临着两种选择:一种是在23点51分到车站3等上3分钟并改乘路线1的车于0点16分到达车站6;另一种是在0点8分到达车站4等上13分钟再换路线1的车于0点31分到达车站6。显然最早我们能在0点16分到达车站6。
任务:
请写一个程序:
l 从文本文件POD.IN中读入对该交通运输网的描述、起点和终点、还有出发的时间;
l 找出从起点到终点的最少时间;
l 把最找到达终点的时间输出到文本文件POD.OUT中。
输入格式:
在文本文件POD.IN的第一行包括六个用空格分开的整数,分别为:
l n,1 £ n £ 1000,为车站的数目;
l k,1 £ k £ 2000,为路线的数目;
l x,1 £ x £ n,为起点的车站编号;
l y,1 £ y £ n,为终点的车站编号;
l gx,0 £ gx £ 23,为出发时间的小时数;
l mx,0 £ mx £ 59,为出发时间的分钟数。
车站是从1到n编号的,运输路线是用1到k编号的。以下的3k行为对运输路线的描述。这些行中每3行构成一个对一条路线的描述,第k个三行的意义如下:
l 第一行包括两个用空格分开的整数,sl(2 £ sl£ n)为该路线上车站的数目,还有cl({6, 10, 12, 15, 20, 30, 60}中的一个元素),为该路线运行的频率;
l 第二行包括sl个用空格分开的不同的整数,为pl,1, pl,2, …,pl,sl(1£ pl,i£ n),即该路线上的车站;
l 第三行包括sl-1个整数rl,1, rl,2, …,rl,sl-1为在路线上相邻两个车站间移动所需的时间(1£ rl,i£ 240)。
在所有的运输路线上的总车站数不超过4000(也就是说s1 + s2 + … + sk £ 4000)。
输出格式:
你的程序应该在文本文件POD.OUT中输出两个整数gy(0£ gy£ 23)和my(0£ my£ 59),表示到达y点时的小时数和分钟数。
样例:
输入(POD.IN):
6 2 5 6 23 30
4 15
1 3 4 6
9 12 10
4 20
5 3 4 2
11 17 11
输出(POD.OUT):
0 16
Solution
这个题还有点说的....
两个限制的最短路,首先可以证明最优性,早到一个点,一定不会比晚到要差
所以我们就可以转化成最短路了
正常的连边,边权记为时间,但是每条边额外记录两个东西(这条路径的频率c,和从这条路径的发车点到这条边需要经过的时间ct)
然后正常的Dijkstra的比较是dis+edge[i].v<dis[edge[i].to进行更新和放入堆中,这里只需要多计算一下等待的时间
有当前的时间,发车的频率,以及车到这个点的时间,就可计算出最快坐上车的时间(最短等待时间)
然后裸上最短路,算出到达终点的最短分钟,然后就可得到答案了
Code
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<queue> using namespace std; void Freopen() {freopen("pod.in","r",stdin); freopen("pod.out","w",stdout);} void Fclose() {fclose(stdin); fclose(stdout);} int read() { int x=0,f=1; char ch=getchar(); while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();} while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();} return x*f; } int N,K,S,T,Gx,Mx; struct EdgeNode{int next,to,t,c,ct,from;}edge[4000<<1]; int head[1010],cnt=1; void AddEdge(int u,int v,int w,int c,int ct) { cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v; edge[cnt].t=w; edge[cnt].c=c; edge[cnt].ct=ct; edge[cnt].from=u; }//c表示频率,ct表示开始时到这个点的时间和,t表示经过这条边的时间 struct CaseNode {int num,c; int R[1001],t[1001],st1[1001],st2[1001]; }cas[2001]; #define Pa pair<int,int> priority_queue<Pa,vector<Pa> , greater<Pa> >q; int dis[1010]; #define INF 0x7fffffff void Dijkstra() { for (int i=1; i<=N; i++) dis[i]=INF; q.push( make_pair(0,S) ); dis[S]=0; int at; while (!q.empty()) { int now=q.top().second; int Dis=q.top().first; q.pop(); for (int i=head[now]; i; i=edge[i].next) { int tmpt=(Dis+Mx-edge[i].ct); while (tmpt<=0) tmpt+=60; tmpt%=60; at=0; if (tmpt%edge[i].c==0) at=Dis; else {int tt=tmpt/edge[i].c; int cz=(tt+1)*edge[i].c-tmpt; at=Dis+cz;} if (at + edge[i].t < dis[edge[i].to]) dis[edge[i].to]=at + edge[i].t,q.push(make_pair(dis[edge[i].to],edge[i].to)); } } } int main() { Freopen(); N=read(),K=read(),S=read(),T=read(),Gx=read(),Mx=read(); for (int i=1; i<=K; i++) { cas[i].num=read(),cas[i].c=read(); for (int j=1; j<=cas[i].num; j++) cas[i].R[j]=read(); for (int j=1; j<=cas[i].num-1; j++) cas[i].t[j]=read(),cas[i].st1[j]=cas[i].st1[j-1]+cas[i].t[j]; for (int j=1; j<=cas[i].num-1; j++) AddEdge(cas[i].R[j],cas[i].R[j+1],cas[i].t[j],cas[i].c,cas[i].st1[j-1]); for (int j=cas[i].num-1; j>=1; j--) cas[i].st2[j]=cas[i].st2[j+1]+cas[i].t[j]; for (int j=cas[i].num; j>=2; j--) AddEdge(cas[i].R[j],cas[i].R[j-1],cas[i].t[j-1],cas[i].c,cas[i].st2[j]); } // for (int i=2; i<=cnt; i++) printf("%d--->%d %d %d %d ",edge[i].from,edge[i].to,edge[i].t,edge[i].c,edge[i].ct); Dijkstra(); // for (int i=1; i<=N; i++) printf("%d ",dis[i]); puts(""); int Gt=(dis[T]+Mx)/60,Mt=dis[T]; printf("%d %d ",(Gt+Gx)%24,(Mt+Mx)%60); Fclose(); return 0; }
启发:
think twice ,code once
要对拍!!T4就因为最后+=XXX写成了++然后就交了,结果炸成20,本来能AK的...
细节地方要反复推敲!