感谢怡巨提供的“1A”训练cf题,没做到几个1A,把代码错误点都再次总结一遍,省赛不能犯这种低级错误
会的1A,不会的瞎搞,这不就是acm的真谛吗?
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;
}
题意:圆桌转圈,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;
}
难点在看题之后的转换,要是把样例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;
}
651A
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;
}
做得特别差的一个题,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;
}
629B
语文水平不够被这个题绕进去了
说要求男女人数相等,且求人数最多的日期
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;
}
659B
一个蠢得不能再蠢的排序题都要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;
}
651B
排序加深搜(相当于并查集吧)
需要严格找当前比自己大的最小的数,那就直接排序从前往后找,用过的数进行标记即可
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