• 山东省第四届ACM省赛


    解题报告:http://www.tuicool.com/articles/FnEZJb

    A.Rescue The Princess(几何,向量)

    B.The number of steps(记忆化搜索,概率dp)

    C.Boring Counting(划分树)

    D.A-Number and B-Number(数位dp,二分答案)

    E.Alice and Bob

    F.Mountain Subsequences(dp)

    G.Rubik’s cube(哈希+bfs)

    H.A^X mod P(转化求幂,打表)

    I.Thrall’s Dream(bfs/dfs)

    J.Contest Print Server(模拟)

    A.Rescue The Princess

    d.逆时针给出两个点A、B,求出逆时针构成正三角形的第三个点C。(即A、B、C为逆时针)

    s.

    法1.

    法2.向量旋转公式,证明见:http://www.cnblogs.com/bofengyu/p/5394969.html

    c.法1

    #include<iostream>
    #include<stdio.h>
    #include<math.h>
    using namespace std;
    
    const double PI=4*atan(1);
    
    int main(){
    
        int T;
        double x1,x2,x3;
        double y1,y2,y3;
        double theta;
        double len;
    
        scanf("%d",&T);
    
        while(T--){
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
    
            theta=atan2(y2-y1,x2-x1);//不能用atan(),原因是atan不分辨一、三象限,也不分辨二、四象限
            len=sqrt((y2-y1)*(y2-y1)+(x2-x1)*(x2-x1));
    
            x3=x1+len*cos(theta+PI/3);
            y3=y1+len*sin(theta+PI/3);
    
            printf("(%.2f,%.2f)
    ",x3,y3);
    
        }
    
        return 0;
    }
    View Code

    c2.法2.向量旋转公式

    #include<iostream>
    #include<stdio.h>
    #include<math.h>
    using namespace std;
    
    const double PI=acos(-1);
    
    int main(){
    
        int T;
        double x1,x2,x3;
        double y1,y2,y3;
        double sin60=sin(PI/3);
        double cos60=cos(PI/3);
    
        scanf("%d",&T);
    
        while(T--){
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
    
            x3=(x2-x1)*cos60-(y2-y1)*sin60+x1;
            y3=(x2-x1)*sin60+(y2-y1)*cos60+y1;
    
            printf("(%.2f,%.2f)
    ",x3,y3);
    
        }
    
        return 0;
    }
    View Code

    B.The number of steps

    C.Boring Counting

    s.应该用划分树

    c.线段树写的超时了。

    /*
    线段树
    单点更新
    */
    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    using namespace std;
    
    #define L(root) ((root)<<1)
    #define R(root) (((root)<<1)|1)
    
    const int MAXN=50010;//
    int numbers[MAXN];//初始值
    int A,B;
    
    struct node{
        int left,right;//
        //int sum;
        int ma,mi;
        int mid(){
            return left+((right-left)>>1);
        }
    }tree[MAXN*4];//4倍空间
    
    void pushUp(int root){
        //tree[root].sum=tree[L(root)].sum+tree[R(root)].sum;
        tree[root].ma=tree[L(root)].ma>tree[R(root)].ma?tree[L(root)].ma:tree[R(root)].ma;
        tree[root].mi=tree[L(root)].mi<tree[R(root)].mi?tree[L(root)].mi:tree[R(root)].mi;
    }
    
    void build(int root,int left,int right){
        tree[root].left=left;
        tree[root].right=right;
        if(left==right){
            //tree[root].sum=numbers[left];
            tree[root].ma=tree[root].mi=numbers[left];
            return;
        }
        int mid=tree[root].mid();
        build(L(root),left,mid);
        build(R(root),mid+1,right);
        pushUp(root);
    }
    
    int query(int root,int left,int right){
        if(tree[root].left==left&&tree[root].right==right){
            //return tree[root].sum;
            if(A<=tree[root].mi&&tree[root].ma<=B){
                return right-left+1;
            }
            if(tree[root].left==tree[root].right){
                return 0;
            }
            int mid=tree[root].mid();
            return query(L(root),left,mid)+query(R(root),mid+1,right);
        }
        int mid=tree[root].mid();
        if(right<=mid){
            return query(L(root),left,right);
        }
        else if(left>mid){
            return query(R(root),left,right);
        }
        else{
            return query(L(root),left,mid)+query(R(root),mid+1,right);
        }
    }
    /*
    void update(int root,int pos,int add){
        if(tree[root].left==tree[root].right){
            tree[root].sum+=add;
            return;
        }
        int mid=tree[root].mid();
        if(pos<=mid){
            update(L(root),pos,add);
        }
        else{
            update(R(root),pos,add);
        }
        pushUp(root);
    }
    */
    
    int main(){
        /*
        memset(numbers,0,sizeof(numbers));
    
        int i;
        for(i=1;i<MAXN;++i){
            numbers[i]=i;
        }
    
        build(1,1,10);
    
        cout<<query(1,2,3)<<endl;
    
        update(1,2,100);
        cout<<query(1,2,3)<<endl;
        */
    
        int T;
        int N,M;
        int L,R;//,A,B;
        int i;
        int Case=0;
    
        scanf("%d",&T);
    
        while(T--){
            scanf("%d%d",&N,&M);
    
            for(i=1;i<=N;++i){
                scanf("%d",&numbers[i]);
            }
            build(1,1,N);
    
            printf("Case #%d:
    ",++Case);
            for(i=0;i<M;++i){
                scanf("%d%d%d%d",&L,&R,&A,&B);
                printf("%d
    ",query(1,L,R));
            }
        }
    
    
        return 0;
    }
    View Code

    D.A-Number and B-Number

    E.Alice and Bob

    F.Mountain Subsequences

    G.Rubik’s cube

    H.A^X mod P

    s.在求A^X幂时,直接快速幂求的话,是O(10^6*log(n)*40)=O(10^9) 肯定会超时。

    我们将X转化成x=i*k+j。这样先在数组可以表示的范围内找到一个k,然后保存(A^0)~(A^k)的值,然后再将求出(A^k)^i 保存在数组里,

    这样每次求A^x,便可以通过这两个数组在O(1)的时间复杂度内求出来,这样时间复杂度就变成了O(10^6*40) = O(4*10^7)了

    #include<iostream>
    #include<stdio.h>
    using namespace std;
    
    #define ll long long
    
    #define N 31622
    #define M 33333
    
    ll powA[N+10];
    ll powB[M+10];
    
    ll n,A,K,a,b,m,P;
    int cas;
    
    void init(){
        powA[0]=1;
        for(int i=1;i<=N;++i){
            powA[i]=powA[i-1]*A%P;
        }
        ll tmp=powA[N];
        powB[0]=1;
        for (int i=1;i<=M;++i){
            powB[i]=powB[i-1]*tmp%P;
        }
    }
    
    void solve(){
        ll fx=K;
        ll ans=0;
        for(int i=1;i<=n;++i){
            ans=(ans+powB[fx/N]*powA[fx%N]%P)%P;
            fx=(a*fx+b)%m;
        }
        printf("Case #%d: %lld
    ",++cas,ans);
    }
    
    int main(){
        int T;
        scanf("%d",&T);
    
        cas=0;
        while (T--){
    
            scanf("%lld%lld%lld%lld%lld%lld%lld",&n,&A,&K,&a,&b,&m,&P);
            init();
            solve();
    
        }
    
        return 0;
    }
    View Code

    I.Thrall’s Dream

    d.这个题意我是着实没大看懂啊。。。英语不好。。

    N个点,M条有向边,问这个图中任意两点是否可以到达。

    s.直接枚举所有点,bfs或者dfs判断是否可达即可。

    c.bfs

    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<queue>
    using namespace std;
    
    #define MAXN 2010
    #define MAXM 10010
    
    struct Edge{
        int to,next;
    }edge[MAXM];
    int head[MAXN],tot;
    
    void addedge(int u,int v){
        edge[tot].to=v;
        edge[tot].next=head[u];
        head[u]=tot++;
    }
    
    void init(){
        tot=0;
        memset(head,-1,sizeof(head));
    }
    
    bool d[MAXN][MAXN];//d[i][j]为true表示i可达j
    bool vis[MAXN];
    
    void bfs(int t){
        memset(vis,false,sizeof(vis));
    
        queue<int>myQueue;
        int u,v;
        int i;
    
        myQueue.push(t);
        vis[t]=true;
    
        while(!myQueue.empty()){
            u=myQueue.front();
            myQueue.pop();
    
            for(i=head[u];i!=-1;i=edge[i].next){
                v=edge[i].to;
                if(!vis[v]){
                    d[t][v]=true;
                    vis[v]=true;
                    myQueue.push(v);
                }
            }
    
        }
    }
    
    int main(){
    
        int T;
        int N,M;
        int u,v;
        int i,j;
        bool flag;//
        int Case=0;
    
        scanf("%d",&T);
    
        while(T--){
            scanf("%d%d",&N,&M);
    
            init();
            for(i=0;i<M;++i){
                scanf("%d%d",&u,&v);
                addedge(u,v);
            }
    
            memset(d,false,sizeof(d));
            for(i=1;i<=N;++i){
                bfs(i);
            }
    
            flag=true;
            for(i=1;i<=N&&flag;++i){
                for(j=1;j<=N&&flag;++j){
                    if(i==j){
                        continue;
                    }
                    if(d[i][j]||d[j][i]){
                        continue;
                    }
                    flag=false;
                    break;
                }
            }
    
            if(flag){
                printf("Case %d: Kalimdor is just ahead
    ",++Case);
            }
            else{
                printf("Case %d: The Burning Shadow consume us all
    ",++Case);
            }
    
        }
    
        return 0;
    }
    View Code

    c2.dfs

    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    using namespace std;
    
    #define MAXN 2010
    #define MAXM 10010
    
    struct Edge{
        int to,next;
    }edge[MAXM];
    int head[MAXN],tot;
    
    void addedge(int u,int v){
        edge[tot].to=v;
        edge[tot].next=head[u];
        head[u]=tot++;
    }
    
    void init(){
        tot=0;
        memset(head,-1,sizeof(head));
    }
    
    bool d[MAXN][MAXN];//d[i][j]为true表示i可达j
    bool vis[MAXN];
    
    void dfs(int t,int t2){
        d[t][t2]=true;
        vis[t2]=true;
    
        int v;
        int i;
        for(i=head[t2];i!=-1;i=edge[i].next){
            v=edge[i].to;
            if(!vis[v]){
                dfs(t,v);
            }
        }
        
    }
    
    int main(){
    
        int T;
        int N,M;
        int u,v;
        int i,j;
        bool flag;//
        int Case=0;
    
        scanf("%d",&T);
    
        while(T--){
            scanf("%d%d",&N,&M);
    
            init();
            for(i=0;i<M;++i){
                scanf("%d%d",&u,&v);
                addedge(u,v);
            }
    
            memset(d,false,sizeof(d));
            for(i=1;i<=N;++i){
                memset(vis,false,sizeof(vis));
                dfs(i,i);
            }
    
            flag=true;
            for(i=1;i<=N&&flag;++i){
                for(j=1;j<=N&&flag;++j){
                    if(i==j){
                        continue;
                    }
                    if(d[i][j]||d[j][i]){
                        continue;
                    }
                    flag=false;
                    break;
                }
            }
    
            if(flag){
                printf("Case %d: Kalimdor is just ahead
    ",++Case);
            }
            else{
                printf("Case %d: The Burning Shadow consume us all
    ",++Case);
            }
    
        }
    
        return 0;
    }
    View Code

    J.Contest Print Server

    s.模拟。注意:某个请求没完成的话,要从第一张开始打印(刚开始没细读题,就写成继续打印了)。

    ps:when the printed pages counter reached s

    这个reached,呵呵,应该是大于吧。

    代码写的是当纸张大于等于s时,就更新s并且counter清零的话,wrong了。。

    #include<iostream>
    #include<stdio.h>
    using namespace std;
    
    int main(){
    
        int T;
        int n,s,x,y,mod;
        int i;
        char team_name[105][25];//名字
        char str[20];
        int p[105];//需要纸张数
        int counter;//当前已输出记数
    
        scanf("%d",&T);
    
        while(T--){
    
            scanf("%d%d%d%d%d",&n,&s,&x,&y,&mod);
    
            for(i=0;i<n;++i){
                scanf("%s%s%d%s",team_name[i],str,&p[i],str);
            }
    
            counter=0;
            for(i=0;i<n;++i){
    
                if(counter+p[i]<=s){//可以打印完
                    printf("%d pages for %s
    ",p[i],team_name[i]);
                    counter+=p[i];
                }
                else{//counter+p[i]>s,不能打印完
                    printf("%d pages for %s
    ",s-counter,team_name[i]);
                    s=(s*x+y)%mod;
                    counter=0;
    
                    while(p[i]>s){//不能打印完
                        printf("%d pages for %s
    ",s,team_name[i]);
                        s=(s*x+y)%mod;
                        counter=0;
                    }
                    
                    printf("%d pages for %s
    ",p[i],team_name[i]);
                    counter+=p[i];
                    
                }
    
            }
    
            printf("
    ");
    
        }
    
        return 0;
    }
    View Code
  • 相关阅读:
    SDUST OJ 时间类的加、减法赋值运算
    POJ 2823 (滑动窗口)
    POJ 2229 计数DP
    POJ 1995 (快速幂)
    poj 3009 (深搜求最短路)
    C++ 学习笔记之 STL 队列
    C++ 学习笔记之 引用
    Anaconda3使用
    Ubuntu 18.04安装Conda、Jupyter Notebook、Anaconda
    Ubuntu 18.04安装 pyenv、pyenv-virtualenv、virtualenv、Numpy、SciPy、Pillow、Matplotlib
  • 原文地址:https://www.cnblogs.com/gongpixin/p/5327863.html
Copyright © 2020-2023  润新知