广东工业大学2016校赛决赛-网络赛 D E F G 题解

来源:互联网 发布:aes解密算法 编辑:程序博客网 时间:2024/04/30 09:54

D二叉树的中序遍历

看似复杂……实则水题;

在纸上画画,发现不满足题意的情况只有一种:##连在一起。其他情况有至少有一种途径可以构造出一颗满足题意的二叉树。但是可能做比赛的时候怕会有坑。。。但实际上真的就是这么简单。。

/* ***********************************************Author        :angon************************************************ */#include <stdio.h>char s[maxn];int main(){    //freopen("in.txt","r",stdin);    //freopen("out.txt","w",stdout);    int t;    scan(t);    while(t--)    {        scanf("%s",s);        int len=strlen(s);        int flag=1;        for(int i=0;i<len;i++)        {            if(s[i]=='#'&&s[i+1]=='#')            {                printf("no\n");                flag=0;                break;            }        }        if(flag)        printf("yes\n");    }    return 0;}

G :我是水题。

吐槽:题目介绍说没有空格,但是实际上有空格,无端wa一次!

/* ***********************************************Author        :angon************************************************ */#include <stdio.h>#include <string.h>#include <iostream>#include <algorithm>#include <stack>#include <vector>#include <queue>#include <set>#include <map>#include <string>#include <math.h>#include <stdlib.h>#include <time.h>using namespace std;#define REP(i,k,n) for(int i=k;i<n;i++)#define REPP(i,k,n) for(int i=k;i<=n;i++)#define scan(d) scanf("%d",&d)#define scann(n,m) scanf("%d%d",&n,&m)#define LL long long#define maxn 1005#define mod 100000007/*inline int read(){    int s=0;    char ch=getchar();    for(; ch<'0'||ch>'9'; ch=getchar());    for(; ch>='0'&&ch<='9'; ch=getchar())s=s*10+ch-'0';    return s;}inline void print(int x){    if(!x)return;    print(x/10);    putchar(x%10+'0');}*/ int main(){    //freopen("in.txt","r",stdin);    //freopen("out.txt","w",stdout);    char s[3000];    int t;    scan(t);    getchar();    while(t--)    {        gets(s);        int len=strlen(s);        int c[30];        memset(c,0,sizeof(c));        for(int i=1;i<len;i+=3)        {            if(c[s[i]-97]==0)                c[s[i]-97]++;         }        int ans=0;        for(int i=0;i<=26;i++)        {                if(c[i])                    ans++;        }        printf("%d\n",ans);     }    return 0;}
E 积木积水

一道很不错的思维题,不需要任何算法,但实际上并没有那么好想。

一旦发现了这个性质就变得非常简单:找到最长的那个柱子,在水满的情况下,从前往后,在它左边水面是非递减的,右边是非递增的(如果从最后一个柱子往中看也是非递减的)

有了这个性质,那么只要从左右各扫一次就可以了;

/* ***********************************************Author        :angon************************************************ */#include <stdio.h>#include <string.h>#include <iostream>#include <algorithm>#include <stack>#include <vector>#include <queue>#include <set>#include <map>#include <string>#include <math.h>#include <stdlib.h>#include <time.h>using namespace std;#define REP(i,k,n) for(int i=k;i<n;i++)#define REPP(i,k,n) for(int i=k;i<=n;i++)#define scan(d) scanf("%d",&d)#define scann(n,m) scanf("%d%d",&n,&m)#define mst(a,k)  memset(a,k,sizeof(a));#define LL long long#define maxn 1000005#define mod 100000007/*inline int read(){    int s=0;    char ch=getchar();    for(; ch<'0'||ch>'9'; ch=getchar());    for(; ch>='0'&&ch<='9'; ch=getchar())s=s*10+ch-'0';    return s;}inline void print(int x){    if(!x)return;    print(x/10);    putchar(x%10+'0');}*/int a[maxn];int main(){    //freopen("in.txt","r",stdin);    //freopen("out.txt","w",stdout);    int n,t;    scan(t);    while(t--)    {        scan(n);        int maxc=-1,idx;        REP(i,0,n)        {            scan(a[i]);            if(a[i]>maxc)            {                maxc=a[i];                idx=i;            }        }        LL sum=0;        int last=a[0];//last表示当前最长的柱子        REP(i,1,idx)        {            if(a[i]<=last)//如果比它短就加上                sum+=(last-a[i]);            else    //否则更新last                last=a[i];        }        last=a[n-1];        for(int i=n-1;i>idx;i--)        {             if(a[i]<=last)                sum+=(last-a[i]);            else                last=a[i];        }        printf("%lld\n",sum);    }    return 0;}

F 我是好人4

容斥 加 dfs枚举子集;

容斥:减去每个数倍数的个数,再把重复减去的加回来;为了达到这个目的:枚举所有子集,子集元素个数奇数的res-=1e9/lcm;

元素个数为偶数的 res+=1e9/lcm;

剪枝:lcm > 1e9 直接return;

优化:1 去重, 2 如果a[i]%a[j]==0,把a[i]去掉;

为什么不会爆:

虽然n<=50 ,子集个数为 2^50-1,但是a[i]<=1000;因为优化2,所以最多就是50个没有直接倍数关系的数,这样必然导致相当一部分a[i]会比较大,这样在剪枝的时候就可以很容易的剪去,

/* ***********************************************Author        :angon************************************************ */#include <stdio.h>#include <string.h>#include <iostream>#include <algorithm>#include <stack>#include <vector>#include <queue>#include <set>#include <map>#include <string>#include <math.h>#include <stdlib.h>#include <time.h>using namespace std;#define REP(i,k,n) for(int i=k;i<n;i++)#define REPP(i,k,n) for(int i=k;i<=n;i++)#define scan(d) scanf("%d",&d)#define scann(n,m) scanf("%d%d",&n,&m)#define mst(a,k)  memset(a,k,sizeof(a));#define LL long long#define maxn 1005#define N 1000000000/*inline int read(){    int s=0;    char ch=getchar();    for(; ch<'0'||ch>'9'; ch=getchar());    for(; ch>='0'&&ch<='9'; ch=getchar())s=s*10+ch-'0';    return s;}inline void print(int x){    if(!x)return;    print(x/10);    putchar(x%10+'0');}*/int cnt,a[55],vis[55];LL ret;LL gcd(LL a,LL b){    return a%b==0?b:gcd(b,a%b);}LL lcm(LL a,LL b){    return a/gcd(a,b)*b;}void dfs(int num,int f, LL tmp){    if(tmp > N ) return ;    if(num == cnt)    {        if(f&1) ret -= (N/tmp);        else ret += (N/tmp);        return ;    }    dfs(num+1,f,tmp);    dfs(num+1,f+1,lcm(a[num],tmp));}int main(){    //freopen("in.txt","r",stdin);    //freopen("out.txt","w",stdout);    int t,n;    scan(t);    while(t--)    {        scan(n);        REP(i,0,n) scan(a[i]);        mst(vis,0);        sort(a,a+n);        for(int i=0;i<n;i++){            if(vis[i]) continue;            for(int j=i+1;j<n;j++){                if(a[j]%a[i]==0)                    vis[j]=1;            }        }        cnt=0;        REP(i,0,n)            if(vis[i]==0)                a[cnt++]=a[i];        ret=0;        dfs(0,0,1LL);        printf("%lld\n",ret);    }    return 0;}

0 0