CSP 2020 AC code

J-T1 power

//T1
#include<cstdio>
using namespace std;
int n;
int main(){
    scanf("%d",&n);
    if(n&1){//判断奇数
        printf("-1");
        return 0;
    }
    for(int i=23;i>=1;--i)//log(2,1e7)≈23.3
        if(n&(1<<i))
            printf("%d ",(1<<i));
    return 0;
}

J-T2 live

//T2
#include<cstdio>
#include<algorithm>
using namespace std;
int bucket[601],n,w,sum,tot,x;
int main(){
    scanf("%d%d",&n,&w);
    for(int i=1;i<=n;++i){
        scanf("%d",&x);
        ++bucket[x];//桶记录
        tot=bucket[600],sum=max(1,i*w/100);//tot记录当前人数,sum记录目标人数
        for(int j=599;j>=0;--j){//x∈[0,600]
            tot+=bucket[j];
            if(tot>=sum){
                printf("%d ",j);
                break;//进行下一轮读入
            }
        }
    }
    return 0;
}

J-T3 expr

//T3
#include<cstdio>
#include<stack>
using namespace std;
struct node{
    bool res;//res:记录遍历到此节点的返回值
    bool flag;//flag:记录是否取反
    int op;//op:为正代表变量的下标,-2代表and,-3代表or
    int ls,rs;//ls:左子节点,rs:右子节点
}expr[1000011];//往大里开
bool v[100011];//v[]记录每个变量的值
bool unwork[100011];//unwork[]记录每个变量的改变是否会影响结果
stack<int> s;//stack[]用于读入表达式的同时建树
int n,q;//题目中的变量
int tot;//tot记录操作符和变量的总个数(除not外)
void mark(int i){//用于标记i及i的子节点
    if(i==-1)//无子节点退出
        return;
    if(expr[i].op>0 && unwork[expr[i].op])//若该节点已被标记,则该节点的子节点一定已被标记,无需再一次进行标记
        return;
    if(expr[i].op>0)//变量要进行标记,并且不必再递归
        unwork[expr[i].op]=true;//标记
    else{//不是变量要递归
        mark(expr[i].ls);//对左子树下的节点进行标记
        mark(expr[i].rs);//对右子树下的节点进行标记
    }
}
int main(){
    char c;
    while((c=getchar())>=32){//输入共一行,读到<32的字符就结束
        if(c==32)//空格跳过
            continue;
        if(c=='x'){//变量
            int x;
            scanf("%d",&x);
            expr[++tot].op=x;//记录变量下标
            expr[tot].ls=expr[tot].rs=-1;//无左右子树
            s.push(tot);//自己入栈
        }
        if(c=='!')
            expr[s.top()].flag^=1;//对not对参数进行标记
        if(c=='&'){
            expr[++tot].op=-2;//记为and
            expr[tot].ls=s.top();//记录栈顶为左子树
            s.pop();//栈顶出栈
            expr[tot].rs=s.top();//记录栈顶为右子树
            s.pop();//栈顶出栈
            s.push(tot);//自己入栈
        }
        if(c=='|'){
            expr[++tot].op=-3;//记为or
            expr[tot].ls=s.top();//记录栈顶为左子树
            s.pop();//栈顶出栈
            expr[tot].rs=s.top();//记录栈顶为右子树
            s.pop();//栈顶出栈
            s.push(tot);//自己入栈
        }
    }
    scanf("%d",&n);
    for(int i=1;i<=n;++i){
        while((c=getchar())<=32);//去空格
        v[i]=c-'0';
    }
    for(int i=1;i<=tot;++i){//对每个子节点进行赋值
        if(expr[i].op>0)//变量
            expr[i].res=v[expr[i].op],expr[i].res^=expr[i].flag;
        if(expr[i].op==-2){//and
            bool res1=expr[expr[i].ls].res;//记录左子树的值
            if(!res1)//为0则对右子树标记为对结果无影响
                mark(expr[i].rs);
            bool res2=expr[expr[i].rs].res;//对右子树进行相同的操作
            if(!res2)
                mark(expr[i].ls);
            expr[i].res=res1&res2;//结果
            expr[i].res^=expr[i].flag;//取反
        }
        if(expr[i].op==-3){//or
            bool res1=expr[expr[i].ls].res;//记录左子树的值
            if(res1)//为1则对右子树标记为对结果无影响
                mark(expr[i].rs);
            bool res2=expr[expr[i].rs].res;//对右子树进行相同操作
            if(res2)
                mark(expr[i].ls);
            expr[i].res=res1|res2;//结果
            expr[i].res^=expr[i].flag;//取反
        }
    }
    scanf("%d",&q);
    while(q--){
        int x;
        scanf("%d",&x);
        printf("%d
",unwork[x]?expr[tot].res:!expr[tot].res);//如果对结果无影响直接输出当前结果,否则输出取反的结果
    }
}

J-T4 number

//T4
#include<cstdio>
using namespace std;
typedef long long LL;
const LL INF=-(1e10);//数据范围内无穷小(1e3*1e3*1e4),要用LL记录
int n,m,num[1001][1001];
LL f[1001][1001][2];
//记忆化搜索,f[i][j][k]记录搜索至[i][j]时搜索的上一步为k的值(k:0->上,1->下)
LL max(LL x,LL y,LL z){return z==0?(x>y?x:y):max(max(x,y,0),max(y,z,0),0);}
//自己写的三个LL比大小
LL dfs(int x,int y,int op){
    if(x<1 || x>n || y<1 || y>m)//边界判定
        return INF;
    if(f[x][y][op]!=INF)//由于是逆向搜索,搜到过的一定是最优解,不必用vis[][]记录是否已访问
        return f[x][y][op];
    return f[x][y][op]=max(dfs(x+(op*2-1),y,op),dfs(x,y-1,0),dfs(x,y-1,1))+num[x][y];
    //Line 15 等价于下面多行注释的代码段
    /*
    if(op==0)//上一步为向上,这一步不能向下只能向上
        f[x][y][op]=max( dfs(x-1,y,0) , dfs(x,y-1,0) , dfs(x,y-1,1) );//如果从左边来,就必须判断两个方向
    if(op==1)//上一步为向下,这一步不能向上只能向下
        f[x][y][op]=max( dfs(x+1,y,1) , dfs(x,y-1,0) , dfs(x,y-1,1) );//同理
    return f[x][y][op];
    */
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j){
            scanf("%d",&num[i][j])
            f[i][j][0]=f[i][j][1]=INF;//先记为无穷小
    }
    f[1][1][0]=f[1][1][1]=num[1][1];//初始化
    printf("%lld",dfs(n,m,0));//如果写成dfs(n,m,1)则无法搜到(n-1,m),但无论如何一定会搜到(n,m-1)
    return 0;
}

S-T1 julian

//T1
#include<cstdio>
using namespace std;
int D[13]={0,31,29,31,30,31,30,31,31,30,31,30,31};//记录每个月的天数(其实因为特判2月可以不计)
struct pair{int x,y;};
pair date(int x,bool rn){//返回一年内的第x天是几月几日(rn表示是否为闰年)(x=0->1月1日)
    int t=0;//t记录模拟到第t天
    pair res;//用pair记录,其中x表示月份,y表示日期
    res.x=res.y=1;//初始化为1月1日
    while(t!=x){//懒得打数学算法,一年内用模拟即可
        t++;
        res.y++;//天数++
        if(res.y>=29){//天数大于29时就有可能到下个月
            if(res.x==2){//2月的特判
                if(!rn && res.y==29){//不是闰年,只有28天
                    res.x=3,res.y=1;//3月1日
                }
                if(rn && res.y==30){//是闰年,有29天
                    res.x=3,res.y=1;//3月1日
                }
            }
            else{
                if(res.y>D[res.x]){//超过月份边界
                    res.x++;res.y=1;//下一个月1日
                }
            }
        }
    }
    return res;
}
void g(long long x){//读入的x为儒略历(本函数中的y均表示年份)
    if(x<=1721423){//-1/12/31
        int y=-4713;
        y+=4*(x/1461);//4年一闰年,一周期共365*4+1=1461天
        x%=1461;
        if(x<366){//该周期的第一年是闰年
            printf("%d %d %d BC
",date(x,true).y,date(x,true).x,-y);
            return;//记得返回,不然可能TLE
        }
        else{
            x--;//去掉闰年多的一天,看成平年
            y+=x/365;
            x%=365;
            printf("%d %d %d BC
",date(x,false).y,date(x,false).x,-y);
            return;
        }
    }
    if(x>=1721424 && x<=2299160){//1/1/1~1582/10/4
        x-=1721424;//从1/1/1开始计算
        int y=1;//年份初始化为1
        y+=4*(x/1461);//同上,使用格里高利历前依然为4年一闰年
        x%=1461;//同上
        if(x<1095){//这次是前3年是平年
            y+=x/365;
            x%=365;
            printf("%d %d %d
",date(x,false).y,date(x,false).x,y);
            return;
        }
        else{
            y+=3;//去掉前3年
            x-=1095;//同上
            printf("%d %d %d
",date(x,true).y,date(x,true).x,y);
            return;
        }
    }
    if(x>=2299161 && x<=2305813){//1582/10/15~1600/12/31(这部分直接带入比较麻烦,进行特殊处理)
        if(x<=2299238){//1582/10/15~1582/12/31
            x-=2299161;//从1582/10/15开始
            x+=15;//从1582/10/1开始
            if(x>=1 && x<=31){//1582/10/1~31
                printf("%d 10 1582
",x);
                return;
            }
            if(x>=32 && x<=61){//1582/11/1~31
                printf("%d 11 1582
",x-31);
                return;
            }
            if(x>=62 && x<=92){//1582/12/1~31
                printf("%d 12 1582
",x-61);
                return;
            }
        }
        if(x>=2299239 && x<=2299603){//1583/1/1~1583/12/31
            x-=2299239;//从1583/1/1开始
            printf("%d %d 1583
",date(x,false).y,date(x,false).x);
            return;
        }
        if(x>=2299604 && x<=2299969){//1584/1/1~1584/12/31
            x-=2299604;//从1584/1/1开始
            printf("%d %d 1584
",date(x,true).y,date(x,true).x);//闰年!!
            return;
        }
        if(x>=2299970 && x<=2305813){//1585/1/1~1600/12/31
            x-=2299970;//从1585/1/1开始
            int y=1585;//年份初始化为1585
            y+=4*(x/1461);//四年一周期
            x%=1461;//同上
            if(x<1095){//前三年为平年
                y+=x/365;
                x%=365;
                printf("%d %d %d
",date(x,false).y,date(x,false).x,y);
                return;
            }
            else{//第四年(闰年)
                y+=3;
                x-=1095;
                printf("%d %d %d
",date(x,true).y,date(x,true).x,y);
                return;
            }
        }
    }
    if(x>=2305814){//1601/1/1~..
        x-=2305814;//从1601/1/1开始
        long long y=1601;//初始化年份为1601
        y+=400*(x/146097);//400年为1周期,共365*400+24*4+1=146097
        x%=146097;//同上
        if(x<=109572){//前300年
            y+=100*(x/36524);//100年为1周期
            x%=36524;//同上
            if(x<=35064){//前96年
                y+=4*(x/1461);//4年为1周期
                x%=1461;//同上
                if(x<=1095){//前3年为平年
                    y+=x/365;
                    x%=365;
                    printf("%d %d %lld
",date(x,false).y,date(x,false).x,y);
                    return;
                }
                else{//第4年(闰年)
                    y+=3;
                    x-=1095;
                    printf("%d %d %lld
",date(x,true).y,date(x,true).x,y);
                    return;
                }
            }
            else{//第97~100年(由于是前300年,此处的第100年是平年)
                y+=96;//加上前面的96年
                x-=35064;//去掉前面的96年
                y+=x/365;
                x%=365;
                printf("%d %d %lld
",date(x,false).y,date(x,false).x,y);
                return;
            }
        }
        else{//第301~400年
            y+=300;//加上前面的300年
            x-=109572;//去掉前面的300年
            y+=4*(x/1461);//4年1周期
            x%=1461;//同上
            if(x<=1095){//前3年为平年
                y+=x/365;
                x%=365;
                printf("%d %d %lld
",date(x,false).y,date(x,false).x,y);
                return;
            }
            else{//第4年(闰年)
                y+=3;
                x-=1095;
                printf("%d %d %lld
",date(x,true).y,date(x,true).x,y);
                return;
            }
        }
    }
}
int q;
int main(){
    scanf("%d",&q);
    while(q--){
        long long x;//#10数据范围为n<=365*10^9
        scanf("%lld",&x);
        g(x);//处理x
    }
    return 0;
}

S-T2 zoo

//T2
#include<cstdio>
using namespace std;
typedef unsigned long long ull;
int n,m,c,k;
bool in_zoo[65],in_list[65];
int main(){
    scanf("%d%d%d%d",&n,&m,&c,&k);
    ull animals=0;// 动 物 家 族 
    for(int i=1;i<=n;++i){
        ull x;
        scanf("%llu",&x);
        animals|=x;//按位或运算
    }
    for(int i=0;i<=k-1;++i)
        in_zoo[i]=animals&1,animals>>=1;//记录是否有动物第i位为1
    for(int i=1;i<=m;i++){
        int x;
        ull y;
        scanf("%d%llu",&x,&y);
        in_list[x]=true;//记录是否有饲料第i位为1
    }
    int cnt=0;
    for(int i=0;i<=k-1;++i){
        if(in_zoo[i])//如果第i位为1的动物在动物园里,则无论是否需要私聊都可以养
            cnt++;
        else if(!in_list[i])//如果没有第i位为1的动物在动物园里,但第i位为1的动物不需要饲料也可以养
            cnt++;
    }
    ull ans=((ull)(1)<<(ull)(cnt));//直接输出会爆精度
    if(cnt==64 && n==0)//爆ull
        printf("18446744073709551616");
    else if(cnt==0)//ull的0不会输出(Too short on line 1)(?)
        printf("0");
    else
        printf("%llu",(ans-n));
    return 0;
}
原文地址:https://www.cnblogs.com/Ender-hz/p/13940633.html