您的位置:首页 > 其它

清明假期找acm状态

2016-04-04 10:45 453 查看
感谢怡巨提供的“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;
}


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;
}


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;
}


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

http://codeforces.com/contest/659/problem/D
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: