CSU2019_6月月赛

CSU2019_6月月赛总结

还有一半的时间逃出来开始写总结(难题太难不会做溜了溜了)
一A了两个水题,还是比较欣慰,最少比原来的连水题都疯狂wa进步很多,但是难题还是没思路,有思路代码不会实现。
此外,觉得水题虽水,但也需要运用技巧,像E题,hint 中重要的事情说三遍写出了 题目对空间大小的限制 2MB ,显然开数组绝对会炸,写完了开数组排序取中值就觉得不对,立刻换思路,不开数组解决。
E题AC代码: (一个求多余一半的数的个数的问题)

//
//  main.cpp
//  2_E
//
//  Created by 陈冉飞 on 2019/6/2.
//  Copyright © 2019 陈冉飞. All rights reserved.
//

#include <iostream>

using namespace std;

int main(int argc, const char * argv[]) {
    int total;
    scanf("%d",&total);
    int res = 0,cnt = 0,num;
    for (int i = 0; i<total; i++) {
        scanf("%d",&num);
        if (cnt == 0){
            res = num;
        }else if(res == num){
            cnt++;
        }else {
            cnt--;
        }
    }
    cout<<res<<endl;

    return 0;
}

这次的D题,同样也是一道水题,最一开始看到别人疯狂a 自己却一点思路都没有慌的一批,后来一想,怎么都是菜,不会做就不会做了,冷静下来思考了一下就是逐次选取偶数,每次对n进行除二的操作,除出来的数即为偶数,即可以提取的k,给他加到ans 中。最后再输出ans即可。

D题AC代码:

//
//  main.cpp
//  2_D
//
//  Created by 陈冉飞 on 2019/6/2.
//  Copyright © 2019 陈冉飞. All rights reserved.
//

#include <iostream>
using namespace std;
#define ll long long

int main(int argc, const char * argv[]) {
    ll int n,ans = 0;
    scanf("%lld",&n);
    while (n>=2) {
        if (n%2 == 0) {
            ans+=n/2;
        }
        else{
            n--;
            ans+=n/2;
        }
        n/=2;
    }
    cout<<ans<<endl;
    return 0;
}

附加AB题的题解:
A题:
-csuoj2334 正解是Bfs+剪枝。好像不剪枝直接Bfs爆搜也能过??? Bfs: 直接枚举每个方向的速度bfs搜索下去即可。 剪枝:在状态拓展过程中可以去掉一些重复无用的搜索。走一条线的时候,如果出现了前方有一个位子(x,y,z),使得从起点走到这个点的时间小于等于当前点时间的话,无需继续向那个方向继续走了。因为那个方向的取优方案可以通过点(x,y,z)来更新,所以多余步骤可以删除。同时如果搜索到终点的话也可直接退出。
代码:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
char s[110][110][110];
int dp[110][110][110],dx[]={0,0,1,-1,0,0},dy[]={1,-1,0,0,0,0},dz[]={0,0,0,0,-1,1},n,m,l,w;
struct Q{
    int x,y,z;
}u,v,ss,tt;
queue<Q>q;
void bfs(){
     int i,j;
     memset(dp,33,sizeof(dp));
     dp[ss.z][ss.x][ss.y]=0;
     while(!q.empty()) q.pop();
     for(q.push(ss);!q.empty();q.pop()){
        u=q.front();
        if(u.x==tt.x&&u.y==tt.y&&u.z==tt.z) break;
        for(i=0;i<6;i++){
            for(j=1;j<=w;j++){
                v.x=u.x+dx[i]*j;
                v.y=u.y+dy[i]*j;
                v.z=u.z+dz[i]*j;
                if(v.x<0||v.x>=n||v.y<0||v.y>=m||v.z<0||v.z>=l) break;
                    if(s[v.z][v.x][v.y]=='#'||dp[v.z][v.x][v.y]<=dp[u.z][u.x][u.y]) break;
                    if(dp[v.z][v.x][v.y]>dp[u.z][u.x][u.y]+1){
                        dp[v.z][v.x][v.y]=dp[u.z][u.x][u.y]+1;
                        q.push(v);
                    }
                }
            }
        }
        if(dp[tt.z][tt.x][tt.y]<=1e6) printf("%d\n",dp[tt.z][tt.x][tt.y]);
        else printf("-1\n");
}
int main(){
    int i,j,k,t;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d%d%d",&n,&m,&l,&w);
        for(k=0;k<l;k++) for(i=0;i<n;i++) scanf("%s",&s[k][i]);
        for(i=0;i<n;i++){
            for(j=0;j<m;j++){
                for(k=0;k<l;k++){
                    if(s[k][i][j]=='S'){
                        ss.x=i;
                        ss.y=j;
                        ss.z=k;
                    }
                    if(s[k][i][j]=='T'){
                        tt.x=i;
                        tt.y=j;
                        tt.z=k;
                    }
                }
            }
        }
        bfs();
    }
    return 0;
}

B题:
csuoj2336 由于只考虑出现次数的奇偶,所以可以处理出一个26位的二进制数来表示每个字符串,表示每个字母出现次数的奇偶。然后问题就转为求有多少个子集的异或值为0。很容易想到枚举每个子集,但子集数会有2^n个,直接枚举在这题里是过不了的。 这里需要将字符串分为两部分,再分别枚举这两部分的子集的xor值,用个map记录每个xor值的出现次数,这样时间复杂度就降为了 log n * 2^(n/2) 了。
代码:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<map>
using namespace std;
char s[110];
int A[30],cnt[30];
map<int,int>ma;
int main(){
     int i,t,n,len,j,sum;
     scanf("%d",&t);
     while(t--){
         scanf("%d",&n);
         for(i=1;i<=n;i++){
            scanf("%s",s);
            len=strlen(s);
            memset(cnt,0,sizeof(cnt));
            for(j=0;j<len;j++) cnt[s[j]-'a'+1]++;
            sum=0;
            for(j=1;j<=26;j++){
                sum=sum*2;
                if(cnt[j]%2) sum+=1;
            }
            A[i]=sum;
         }

         int k=n/2,m=n-n/2;
         ma.clear();
         int ans=0;
         for(i=1;i<(1<<m);i++){
              sum=0;
              for(j=0;j<m;j++) if((1<<j)&i) sum^=A[j+k+1];
              if(ma.find(sum)==ma.end()) ma[sum]=1;
              else ma[sum]++;
              if(sum==0) ans++;
         }

         for(i=1;i<(1<<k);i++){
              sum=0;
              for(j=0;j<k;j++)  if((1<<j)&i) sum^=A[j+1];
              if(ma.find(sum)!=ma.end()) ans+=ma[sum];
              if(sum==0) ans++;
         }
         printf("%d\n",ans);
     }
     return 0;
}

F题:
数学推导:
x2+y2=r2
⇒y2=(r−x)(r+x)
令d=gcd(r−x,r+x)
则y2=d2∗r+xd∗r−xd
再令A=r+xd,B=r−xd
则y2=d2∗A∗B
考虑y2是完全平方数,d2是完全平方数,又gcd(A,B)=1那么A,B都是完全平方数。

设A=a2,B=b2
A+B=a2+b2
⇒2∗rd=a2+b2

考虑枚举2∗rd,这一步的复杂度是O(r√)的,然后再在[1,2∗rd‾‾‾‾‾√/2]的范围内枚举a,进而可以算出A,b,B,然后判断A,B是否互质,B是否为完全平方数,这样子就算出了第一象限的答案,然后将ans∗4+4,算是统计了每一个象限的并且加上了坐标轴上的四个点。

代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#include<map>
using namespace std;
#define llg long long
#define maxn 100010
#define yyj(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
llg ans,n;
inline llg getint()
{
    llg w=0,q=0; char c=getchar();
    while((c<'0' || c>'9') && c!='-') c=getchar();
    if (c=='-')  q=1, c=getchar(); while (c>='0' && c<='9') w=w*10+c-'0', c=getchar();
    return q ? -w : w;
}

void calc(llg d)
{
    for (llg a=1;a<=sqrt(d/2);a++)
    {
        llg A=a*a,B=d-A,b=sqrt(B);
        if (b*b==B && __gcd(A,B)==1 && A!=B) ans++;
    }
}

int main()
{
    yyj("circle");
    cin>>n;
    for (llg i=1;i<=sqrt(n*2);i++)
        if ((2*n%i)==0)
        {
            calc(i);
            calc(2*n/i);
        }
    cout<<ans*4+4;
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值