不得不说 我太弱 Or 紫书或者太难,肯定是前者。又一次开始刷,选择从第四章开始,不知道是不是个错误…模拟题真的好麻烦,还有纯考智商的题目都写不动,何谈刷。不如当初切搜索水题有快感。
部分代码都存在坏掉电脑里和还没做的题目,有机会再补上。
题目给的思路很清晰,字母可以随意重排,所以和前后位置没有关系,只需要分别统计每个字母出现的次数放在数组里,然后排序,由于是一一对应关系,再将排的序后的数组进行比较,相等说明可一一对应上。注意,这里本想用memcmp,发现不管用。
这题实现不难,主要学会如何用优雅的代码(短小,且易懂)水过。几个变量的取名,子函数的写法等,
这题,也是经典模拟题,我直接看的书,,,绕圈取余就好,一个go函数就实现两个有共性的操作,最优代码,开始还能纳闷p1明明从1开始,怎么带入是n,后来推敲原来这里他每次从出发点到下一点算走两次,就是到出发点也算一次。
[cpp]
#include<cstdio>
#include<cstring>
using namespace std;
int a[25],n,k,m;
int go(int p,int d,int t)
{
while(t--)
{
do{p=(p-1+d+n)%n+1;} while(a[p]==0);
}
return p;
}
int main()
{
while(~scanf("%d %d %d",&n,&k,&m)&&n&&k&&m)
{
for(int i=1;i<=n;i++) a[i]=i;
int left=n,p1=n,p2=1;
while(left)
{
p1=go(p1,1,k);
p2=go(p2,-1,m);
printf("%3d",p1);left--;
if(p2!=p1) {printf("%3d",p2);left--;}
a[p1]=a[p2]=0;
if(left) printf(",");
}
printf("\n");
}
return 0;
这题 也是琢么了好久,数据读入到实现算法当初完全一头雾水…..最坑爹是这题照书上代码会W,看了大牛题解,实现也有点问题,交了竟AC(渣渣 求别笑)考点 三个,换行的读入, 二进制转十进制,还有移位实现乘二。
#include <stdio.h>
#include <string.h>
char code[8][1<<8], s[1<<8];
// 过滤空行,返回字符串长度
int my_gets(char* s) {
int k;
while ((k = getchar()) == '\n'); // 空行重读
if (k == -1) k = 0; else gets(s+1);
s[0] = k; return strlen(s);
}
void init() {
int i, j, k = 0;
for (i = 1; ; i++) {
for (j = 0; j < (1<<i)-1; j++) {
code[i][j] = s[k++];
if (!s[k]) return;
}
}
}
// 读取01字符,返回0、1整型值
int read() {
char ch;
while ((ch = getchar()) == '\n');
return ch - '0';
}
// 读取c个01字符
int readint(int c) {
int v = 0;
while (c--) v = (v<<1)+read();
return v;
}
int main() {
int len, v;
while (my_gets(s)) {
init();
while (len = readint(3))
while ((v = readint(len)) != ((1<<len)-1))
putchar(code[len][v]);
putchar('\n');
}
return 0;
}
这题纯粹的模拟题,自己写的时候,思路神马都对,交了w,之后看书上,还有更好思路的做法,就是先将所有操作保存,然后对每个查询重新执行每个操作对于关注的单元格,而不是对所有的电子表格进行操作。对于题目给定的规模来说,这个方法不仅更好写,而且效率更高。
#include<cstdio>
#include<cstring>
#define maxn 10000
struct command
{
char c[5];
int r1,r2,c1,c2;
int a,x[20];
}cmd[maxn];
int r,c,n;
int simulate(int &r0,int &c0)
{
for(int i=0;i<n;i++)
{
if(cmd[i].c[0]=='E')
{
if(r0==cmd[i].r1&&c0==cmd[i].c1) {r0=cmd[i].r2,c0=cmd[i].c2;}
else if(r0==cmd[i].r2&&c0==cmd[i].c2){r0=cmd[i].r1,c0=cmd[i].c1;}
}
else
{
int dr=0,dc=0;
for(int j=0;j<cmd[i].a;j++)
{
int X=cmd[i].x[j];
if(cmd[i].c[0]=='D')
{
if(cmd[i].c[1]=='R'&&X==r0) return 0;
if(cmd[i].c[1]=='C'&&X==c0) return 0;
if(cmd[i].c[1]=='R'&&X<r0) dr--;
if(cmd[i].c[1]=='C'&&X<c0) dc--;
}
else
{
if(cmd[i].c[1]=='R'&&X<=r0) dr++;
if(cmd[i].c[1]=='C'&&X<=c0) dc++;
}
}
r0+=dr,c0+=dc;
}
}
return 1;
}
int main()
{
int kcase=0;
while(scanf("%d %d",&r,&c)&&r&&c)
{
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%s",cmd[i].c);
if(cmd[i].c[0]=='E')
{
scanf("%d%d%d%d",&cmd[i].r1,&cmd[i].c1,&cmd[i].r2,&cmd[i].c2);
}
else
{
scanf("%d",&cmd[i].a);
for(int j=0;j<cmd[i].a;j++)
scanf("%d",&cmd[i].x[j]);
}
}
if(kcase>0) printf("\n");
printf("Spreadsheet #%d\n",++kcase);
int cnt;
scanf("%d",&cnt);
while(cnt--)
{
int a,b;scanf("%d%d",&a,&b);
printf("Cell data in (%d,%d) ",a,b);
if(!simulate(a,b)) printf("GONE\n");
else printf("moved to (%d,%d)\n",a,b);
}
}
}
4-6 跳过
这题 LRJ大神 翻译的有点瑕疵…Hij代表行,Vij代表列,而V中ij是反过来的,注意读入反过来就好。
题意,告诉你哪些地方有边,然后数构成大小从小打到的正方形分别多少个。
算法就是,从第一个位置作为正方形的左上角开始扫,几个循环控制,最外面是正方形的边长,再是位置的两个循环,再是扫几个单位的循环,思路非常清晰。
#include<cstdio>
#include<cstring>
using namespace std;
int v[15][15],h[15][15],n,m;
int main()
{
int t=0;
while(~scanf("%d %d",&n,&m))
{
getchar();
memset(v,0,sizeof(v));
memset(h,0,sizeof(h));
for(int i=1;i<=m;i++)
{
char c;int a,b;
scanf("%c %d %d",&c,&a,&b);
getchar();
if(c=='V') v[b][a]=1;
else if(c=='H') h[a][b]=1;
}
if(t>0) printf("\n**********************************\n\n");
printf("Problem #%d\n\n",++t);
int l,flag,cnt,sum=0;
for(l=1;l<=n;l++)
{
cnt=0;
for(int i=1;i+l<=n;i++)
{
for(int j=1;j+l<=n;j++)
{
flag=1;
for(int k=j;k<j+l;k++)
if(!h[i][k]||!h[i+l][k]) flag=0;
for(int k=i;k<i+l;k++)
if(!v[k][j]||!v[k][j+l]) flag=0;
cnt+=flag;
}
sum+=cnt;
}
if(cnt)
printf("%d square (s) of size %d\n",cnt,l);
}
if(!sum) printf("No completed squares can be found.\n");
}
}
据说这题应该,枚举24种可能,六个可能做顶面,四个可能做正面的搞,还有模拟旋转的搞法,然而智商做鸡没想纠结,所以我是判断三个对边相等就符合相同正方形。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
char s1[10],s2[10];
int vis[6];
int compare(int x,int y,int a,int b,int c,int d)
{
if(!vis[x]&&!vis[y]&&((s1[x]==s2[x]&&s1[y]==s2[y])||(s1[x]==s2[y]&&s1[y]==s2[x])))
{
vis[x]=vis[y]=1;
return 1;
}
else if(!vis[a]&&!vis[b]&&((s1[x]==s2[a]&&s1[y]==s2[b])||(s1[x]==s2[b]&&s1[y]==s2[a])))
{
vis[a]=vis[b]=1;
return 1;
}
else if(!vis[c]&&!vis[d]&&((s1[x]==s2[c]&&s1[y]==s2[d])||(s1[x]==s2[d]&&s1[y]==s2[c])))
{
vis[c]=vis[d]=1;
return 1;
}
else
return 0;
}
int main()
{
while(~scanf("%6s%6s",s1,s2))
{
memset(vis,0,sizeof(vis));
int cnt=0;
cnt+=compare(0,5,1,4,2,3);
cnt+=compare(1,4,0,5,2,3);
cnt+=compare(2,3,1,4,0,5);
if(cnt==3) printf("TRUE\n");
else printf("FALSE\n");
}
return 0;
}
这题二分被我写得感人,精度问题一直w,快要放弃之前,人品爆发随意加两0过了….教训思路没有明显错误的情况下,二分精度检查是首步。
再说这题,LRJ把这题放在最后一题,明显与难度不符…我觉得前面模拟难写多了….这题把所有格子高度排个序,二分水能淹过的高度。
当然还有别的思路,排序后从第一个最小的开始淹漠,这里也有两种写法。详细就不说了,大神题解里都有。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define eps 1e-10
using namespace std;
double M[100000],sum;
int n,m;
int judge(double c)
{
double s=0;
for(int i=0;i<m*n;i++)
{
if(c>=M[i])
s+=c-M[i];
}
if(s>=sum) return 1;
else return 0;
}
int main()
{
int cnt=0;
while(~scanf("%d %d",&m,&n)&&m&&n)
{
for(int i=0;i<m*n;i++)
scanf("%lf",&M[i]);
sort(M,M+m*n);
scanf("%lf",&sum);
sum/=100;
double l=M[0],r=1000.0;
while(l+eps<=r)
{
double mid=(l+r)*0.5;
if(judge(mid))
r=mid;
else
l=mid+0.0001;//开始是0.01,0.001 都没过,以后写二分一定注意精度问题,一般比题目结果小数后面多两个0。
}
double ans=0;
for(int i=0;i<n*m;i++)
if(M[i]<=r) ans++;
printf("Region %d\n",++cnt);
printf("Water level is %.2lf meters.\n",r);
printf("%.2lf percent of the region is under water.\n",ans*100.0/(double)(n*m));
printf("\n");
}
return 0;
}
第四章,切过水题,告一段落,开始向第五章和动规进发!!!