• 2019-8-15 考试总结


    A. 数论

    数学题,经实践证明,这个题可以$AC$。

    考试时打的暴力,拿到$20$分。

    正解:

    虽然现在思路还是有点模糊,但是大体的思路应该差不多。

    首先,就像题解说的,如果对于一个非良好数$x$,$xp^c$也是非良好数,其中$p$为质数,$c>=0$。

    前提是$x$中不含质因子$p$。

    $xp^c$的约数个数$val[xp^c]$是$val[x] imes (c-1)$。

    $x$中没有质因子$p$,当然他的约数中也没有质因子$p$,所以每次乘$p$都会形成新的约数。

    之后就是一些玄学的操作。

    每次"迭代"$($新名词$)$,把原序列中的数拓展,

    先枚举素数,再枚举原序列中的数,再枚举指数,把新数存到临时的数组中。

    最后删去新的临时数组中不合法的数,因为这个数不会再更新别的数了。

    注意要排序。

    再维护一个堆,维护前$k+1$大的约数个数。

    这样就可以删掉当前不合法的数了,应该是当前,因为之后插进来的数还可能再使它不合法。

    最后一定可以筛掉所有不合法的数。

    最后$TLE70$。

    丑陋的代码:

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<queue>
    #define _min(x,y) ((x)<(y)?(x):(y))
    #define _max(x,y) ((x)>(y)?(x):(y))
    #define _abs(x) ((x)<0?(-1*(x)):(x))
    #define Maxn 1000050
    #define Reg register
    //#define int long long
    #define int __int128
    using namespace std;
    bool vis[Maxn];
    int T,K,m,tot,top[2],pri[Maxn],ans[Maxn];
    struct Node {int x,cnt;} stack[2][Maxn],lss[Maxn];
    bool comp(Node a,Node b) {return a.x<b.x;}
    priority_queue<Node,vector<int>,greater<int> > q;
    void print(int x)
    {
        if(x>=10) print(x/10);
        putchar(x%10+48);
        return;
    }
    signed main()
    {
        scanf("%lld%lld%lld",&T,&K,&m);
        for(Reg int i=2;i<=10000;++i)
        {
            if(vis[i]) continue;
            pri[++tot]=i;
            if(tot==300) break;
            for(Reg int j=2;j*i<=100000;++j) vis[j*i]=1;
        }
        stack[0][++top[0]]=(Node){1,1};
        for(Reg int i=1;i<=tot;++i)
        {
            int cur=i&1,pre=(i+1)&1;
            top[cur]=0;
            for(Reg int j=1;j<=top[pre];++j)
            {
                int lss=1,x=stack[pre][j].x,p=stack[pre][j].cnt;
                for(Reg int k=0;k<=60;++k)
                {
                    if(lss*x>m||lss*x<0) break;
                    stack[cur][++top[cur]]=(Node){lss*x,p*(k+1)};
                    lss*=pri[i];
                }
            }
            sort(stack[cur]+1,stack[cur]+top[cur]+1,comp);
            int tok=0;
            while(!q.empty()) q.pop();
            for(Reg int j=1;j<=top[cur];++j)
            {
                if(stack[cur][j].x==1)
                {
                    if(q.size()>=K+1&&stack[cur][j].cnt-1<q.top()) continue;
                    lss[++tok]=stack[cur][j];
                    q.push(stack[cur][j].cnt-1);
                    while(q.size()>K+1) q.pop();
                }
                else
                {
                    if(q.size()>=K+1&&stack[cur][j].cnt-2<q.top()) continue;
                    lss[++tok]=stack[cur][j];
                    q.push(stack[cur][j].cnt-2);
                    while(q.size()>K+1) q.pop();
                }
            }
            top[cur]=0;
            for(Reg int j=1;j<=tok;++j) stack[cur][++top[cur]]=lss[j];
        }
    //    for(Reg int i=1;i<=top[tot&1];++i) cout<<stack[tot&1][i].x<<endl;
        while(T--)
        {
            int x; scanf("%lld",&x);
            print(stack[tot&1][x].x); puts("");
        }
        return 0;
    }
    View Code

    B. 位运算

    正解:

    用$dp[i][j]$表示第$i$个数,到这时一共有$j$个$1$,这种情况是否存在$(0/1)$。

    记录一下前趋,因为只要一组合法解,所以出现一个记录一个就好了。

    转移的话分三种情况:

    符号为$&$,这时下界是$max(0,j+a[i+1]-m)$,上界是$min(j,a[i+1])$,

    符号为$|$,这时下界是$max(j,a[i+1])$,上界是$min(m,j+a[i+1])$,

    符号为^,这时下界是$|j-a[i+1]|$,上界是$2m-j-a[i+1]$。

    就是这样,然后记录前趋。

    最后用$dfs$还原原数,很麻烦,很多细节。

    丑陋的代码:

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #define _min(x,y) ((x)<(y)?(x):(y))
    #define _max(x,y) ((x)>(y)?(x):(y))
    #define _abs(x) ((x)<0?(-1*(x)):(x))
    #define Maxn 100050
    #define Reg register
    int n,m,c,opt[Maxn],dp[Maxn][35],pre[Maxn][35],A[Maxn],num[Maxn];
    char s[10];
    int get(int x)
    {
        int s=0;
        while(x) {if(x&1) ++s; x>>=1;}
        return s;
    }
    void dfs(int now,int st)
    {
        if(now==1) {num[1]=st; return;}
        if(opt[now-1]==1)
        {
            int nxt=pre[now][get(st)],nst=st,npt=st;
            for(Reg int i=1;i<=m;++i)
            {
                if(get(nst)==nxt) break;
                if(!(nst&(1<<(i-1)))) nst|=(1<<(i-1));
            }
            for(Reg int i=1;i<=m;++i)
            {
                if(get(npt)==A[now]) break;
                if(((st&(1<<(i-1)))&&!(nst&(1<<(i-1))))) npt|=(1<<(i-1));
                else if((!(st&(1<<(i-1)))&&!(nst&(1<<(i-1))))) npt|=(1<<(i-1));
            }
            num[now]=npt; dfs(now-1,nst);
        }
        else if(opt[now-1]==2)
        {
            int nxt=pre[now][get(st)],nst=st;
            for(Reg int i=1;i<=m;++i)
            {
                if(get(nst)==nxt) break;
                if(nst&(1<<(i-1))) nst^=(1<<(i-1));
            }
            int npt=nst^st;
            for(Reg int i=1;i<=m;++i)
            {
                if(get(npt)==A[now]) break;
                if(nst&(1<<(i-1))) npt|=(1<<(i-1));
            }
            num[now]=npt; dfs(now-1,nst);
        }
        else
        {
            int nxt=pre[now][get(st)],nst=0,npt=0;
            for(Reg int i=1;i<=m;++i)
            {
                if(!(st&(1<<(i-1)))) continue;
                if(get(nst)<nxt) nst|=(1<<(i-1));
                else npt|=(1<<(i-1));
            }
            for(Reg int i=1;i<=m;++i)
            {
                if(nxt-get(nst)==A[now]-get(npt)) break;
                if(nxt-get(nst)>A[now]-get(npt)&&(npt&(1<<(i-1)))&&!(nst&(1<<(i-1)))) nst^=(1<<(i-1)),npt^=(1<<(i-1));
                if(nxt-get(nst)<A[now]-get(npt)&&(nst&(1<<(i-1)))&&!(npt&(1<<(i-1)))) nst^=(1<<(i-1)),npt^=(1<<(i-1));
            }
            for(Reg int i=1;i<=m;++i)
                if(!(st&(1<<(i-1)))&&get(nst)<nxt&&get(npt)<A[now]) nst|=(1<<(i-1)),npt|=(1<<(i-1));
            num[now]=npt; dfs(now-1,nst);
        }
        return;
    }
    int main()
    {
        scanf("%d%d%d",&n,&m,&c);
        for(Reg int i=1;i<=n-1;++i)
        {
            scanf("%s",s);
            if(s[0]=='A') opt[i]=1;
            else if(s[0]=='O') opt[i]=2;
            else opt[i]=3;
        }
        for(Reg int i=1;i<=n;++i) scanf("%d",&A[i]);
        dp[1][A[1]]=1;
        for(Reg int i=1;i<=n-1;++i)
        {
            for(Reg int j=0;j<=m;++j)
            {
                if(!dp[i][j]) continue;
                if(opt[i]==1) for(Reg int k=_max(0,j-(m-A[i+1]));k<=_min(j,A[i+1]);++k) dp[i+1][k]=1,pre[i+1][k]=j;
                else if(opt[i]==2) for(Reg int k=_max(j,A[i+1]);k<=_min(m,j+A[i+1]);++k) dp[i+1][k]=1,pre[i+1][k]=j;
                else
                {
                    int mxx=(m-A[i+1]>j)?(A[i+1]+j):(2*m-j-A[i+1]);
                    for(Reg int k=_abs(j-A[i+1]);k<=mxx;k+=2) dp[i+1][k]=1,pre[i+1][k]=j;
                }
            }
        }
        if(!dp[n][get(c)]) printf("OvO");
        else
        {
            dfs(n,c);
            for(Reg int i=1;i<=n;++i) printf("%d ",num[i]);
        }
        return 0;
    }
    View Code

    C. 旅行

    总结:

    这次考试题目挺好的,做题改题都挺费劲的。

    其实这次考试也没必要谈心态,因为心态好了也想不出来。。。

    说考试过程吧,

    前$40$分钟看$T1$,开始打$k=0$的表,企图能找到一些规律。

    发现前几项非常像等差数列。。其实没什么规律。

    而且暴力分给的非常少。

    之后看$T2$,发现居然有暴力分。。

    打完搜索,然后看特殊性质$1$,应该能拿到一些分。

    然后码了一个小时左右,嗯,以为$T2$的暴力分能拿满。

    最后$T3$,心想可能教练故意难度递减排序,应该可做,然后想了一会儿,还是不可做。。

    滚回去看$T1$,依然没什么思路,快速码了一个暴力,水到$20$分。

    最后$20+10+0=30$。

    没什么水平。。。

  • 相关阅读:
    微信支付可能改变的六大行业
    WeChat Official Account Admin Platform API Introduction
    WeChat Official Account Admin Platform Message API Guide
    微信公众平台开发(61)预约挂号
    PHP获取Cookie模拟登录
    微信公众平台开发(60)每日英语
    微信公众平台开发(59)相册
    SQL语句执行顺序
    sql
    pthread_rwlock_t
  • 原文地址:https://www.cnblogs.com/Milk-Feng/p/11360753.html
Copyright © 2020-2023  润新知