感谢怡巨提供的“1A”训练cf题,没做到几个1A,把代码错误点都再次总结一遍,省赛不能犯这种低级错误
会的1A,不会的瞎搞,这不就是acm的真谛吗?
629A
1A过的
题意:统计有多少个匹配,一个匹配意味着有两个C字母在同一行或者一列
暴力统计每行每列的C字母个数,然后一个求和公式就搞定
int row[maxn]; int col[maxn]; int n; char mp[maxn][maxn]; int main(){ //input; while(scanf("%d",&n)!=EOF){ for(int i=1;i<=n;i++) scanf("%s",mp[i]+1); memset(row,0,sizeof(row)); memset(col,0,sizeof(col)); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if (mp[i][j]=='C') row[i]++,col[j]++; int ans=0; for(int i=1;i<=n;i++) ans+=(row[i]-1)*row[i]/2; for(int i=1;i<=n;i++) ans+=(col[i]-1)*col[i]/2; printf("%d\n",ans); } return 0; }
659A
题意:圆桌转圈,n个点,需要从起点走到终点,已知步数
1A过的,很简单,步数对点数取余之后,根据正负处理走向即可
int n,a,b; int main(){ //input; while(scanf("%d%d%d",&n,&a,&b)!=EOF){ b=b%n; a+=b; while(a>=n) a-=n; while(a<=0) a+=n; cout<<a<<endl; } return 0; }
659C
难点在看题之后的转换,要是把样例2的output写成1235肯定可以看出来怎么做了
方法是贪心:从1一直往后算,只要没有出现过并且买得起就买,记得用二分搜索判断是否在原数组中出现过,因此预处理需要排序
int n,m,ans,Left; int num[maxn]; int ansnum[maxn]; bool canfind(int x){ int l=1,r=n,mid; while(l<=r){ mid=(l+r)>>1; if (num[mid]==x) return true; else if (num[mid]>x) r=mid-1; else l=mid+1; } return false; } int main(){ //input; while(scanf("%d",&n)!=EOF){ scanf("%d",&m); for(int i=1;i<=n;i++) scanf("%d",&num[i]); sort(num+1,num+n+1); ans=0; Left=m; for(int i=1;i<=m;i++){ if (Left<i) break; if (!canfind(i)){ ans++; Left-=i; ansnum[ans]=i; } } printf("%d\n",ans); for(int i=1;i<=ans;i++) printf("%d%c",ansnum[i],i==ans?'\n':' '); } return 0; }
2A过的是因为没有处理边界(题目的意思我没懂1 1这种特殊情况到底应该怎么算)
有很多方法做这个题,数据量最大100*100,暴力两重for应该也能过的
选用记忆化DP是因为代码好写,从输入的nm倒着来就好
int dp[maxn][maxn]; int getdp(int x,int y){ if (dp[x][y]!=-1) return dp[x][y]; if (x<=0||y<=0) return dp[x][y]=0; if (x==1) return dp[x][y]=getdp(x+1,y-2)+1; if (y==1) return dp[x][y]=getdp(x-2,y+1)+1; return dp[x][y]=max(getdp(x+1,y-2),getdp(x-2,y+1))+1; } int main(){ int n,m; memset(dp,-1,sizeof(dp)); while(scanf("%d%d",&n,&m)!=EOF){ if (n==1&&m==1) cout<<"0"<<endl; else printf("%d\n",getdp(n,m)); } return 0; }
651C
做得特别差的一个题,5A
错因只有一个:不知道怎么判定边界,即现在处理的数据是不是在输入的数据集合
因为要for循环找符合条件的,如何给定限制,又符合题意条件又处理好了最后一个数的边界,换了好多种表示
题意是找到给定点集中,两点的定义的两个距离相等的数目对
即为:629A
只需要排序之后,统计在同一直线上的点的数目即可
还有一个自己避免了的wa点:__int64
struct node{ int x,y; }a[maxn]; int n; int cmpx(node m,node n){ if (m.x==n.x) return m.y<n.y; return m.x<n.x; } int cmpy(node m,node n){ if (m.y==n.y) return m.x<n.x; return m.y<n.y; } int main(){ //input; int i,j; __int64 ans,temp; while(scanf("%d",&n)!=EOF){ for(i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].y); ans=0; sort(a+1,a+n+1,cmpx); for(i=1;i<=n;){ temp=0; for(j=i;j<=n;j++) if (a[j].x==a[i].x) temp++; else break; ans+=temp*(temp-1)/2; i=j; } sort(a+1,a+n+1,cmpy); for(i=1;i<=n;){ temp=0; for(j=i;j<=n;j++) if (a[j].y==a[i].y) temp++; else break; ans+=temp*(temp-1)/2; i=j; } for(i=1;i<=n;){ temp=0; for(j=i;j<=n;j++) if (a[j].x==a[i].x&&a[j].y==a[i].y) temp++; else break; ans-=temp*(temp-1)/2; i=j; } printf("%I64d\n",ans); } return 0; }
语文水平不够被这个题绕进去了
说要求男女人数相等,且求人数最多的日期
3A才过是因为:不是符合男女人数相等的日期才有意义,而是每个日期中,选择男女人数较少的那个,然后再匹配异性不就ok了吗?
表达可能还是比较绕,看了代码肯定明白:
struct node{ char s[5]; int x,y; }a[maxn]; int n,man,woman,ans; int main(){ //input; while(scanf("%d",&n)!=EOF){ ans=0; for(int i=1;i<=n;i++) scanf("%s%d%d",a[i].s,&a[i].x,&a[i].y); for(int i=1;i<=366;i++){ man=woman=0; for(int j=1;j<=n;j++) if (a[j].x<=i&&a[j].y>=i) if (a[j].s[0]=='M') man++; else woman++; man=min(man,woman); ans=max(ans,man*2); } printf("%d\n",ans); } return 0; }
一个蠢得不能再蠢的排序题都要2A
是个赶紧退役的理由了
题意中强调每个组别至少两个人:意味着该组只有两个人的时候肯定有解
否则一定要该组的最大值和次大值比第三大值严格大
wa的一发没有判断该组两个人的情况
struct node{ string s; int pos; int score; }a[maxn],ans1,ans2; int cmp(node x,node y){ if (x.pos==y.pos) return x.score>y.score; return x.pos<y.pos; } int main(){ //input; int n,m,i,j,pos,flag,num; while(scanf("%d%d",&n,&m)!=EOF){ for(i=1;i<=n;i++){ cin>>a[i].s; scanf("%d%d",&a[i].pos,&a[i].score); } sort(a+1,a+n+1,cmp); pos=1;j=1; while(pos<=m){ flag=false; i=j; j=i+1; while(a[i].pos==a[j].pos) j++; num=j-i; if (num==2){ ans1=a[i]; ans2=a[i+1]; flag=true; } else if (a[i].score>a[i+2].score&&a[i+1].score>a[i+2].score &&a[i].pos==a[i+2].pos&&a[i+1].pos==a[i+2].pos){ ans1=a[i]; ans2=a[i+1]; flag=true; } pos++; if (flag) cout<<ans1.s<<" "<<ans2.s<<endl; else cout<<"?"<<endl; } } return 0; }
排序加深搜(相当于并查集吧)
需要严格找当前比自己大的最小的数,那就直接排序从前往后找,用过的数进行标记即可
2A是因为在dfs中忘了对vis数组进行标记,蠢成。。。
小技巧是设置inf作为边界标记,到了之后就到头了
int n,a[maxn],ans; bool vis[maxn]; void dfs(int pos){ int i; for(i=pos+1;;i++) if (a[i]>a[pos]&&!vis[i]) break; if (a[i]==inf) return; else{ vis[i]=true; ans++; dfs(i); } return; } int main(){ //input; while(scanf("%d",&n)!=EOF){ for(int i=1;i<=n;i++) scanf("%d",&a[i]); a[n+1]=inf; sort(a+1,a+n+1); memset(vis,0,sizeof(vis)); ans=0; for(int i=1;i<=n;i++) if (!vis[i]){ vis[i]=true; dfs(i); } printf("%d\n",ans); } return 0; }
做了这些题之后发现简单题的代码思想基本都在
暴力,搜索,简单dp
需要再上一层楼估计很难,也没有那么多的时间来学习新的算法
省赛需要做的就是把简单细节做好
还有两个坑等待填,暂时不会
http://codeforces.com/contest/629/problem/C
http://codeforces.com/contest/659/problem/D