zoukankan      html  css  js  c++  java
  • NCPC 2016:简单题解

    A .Artwork

    pro:给定N*M的白色格子,然后Q次黑棒,输出每次加黑棒后白色连通块的数量。(N,M<1e3, Q<1e4)

    sol:倒着离线做,并查集即可。

    (在线做法:https://www.cnblogs.com/asdfsag/p/10485607.html

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn = 1e6 + 10;
    int a[1010][1010], fa[maxn], ID[1010][1010];
    struct node
    {
        int x1, y1, x2, y2;
        node(){}
        node(int x1, int y1, int x2, int y2):x1(x1), y1(y1), x2(x2), y2(y2){}
    }c[maxn];
    int Find(int x){return x == fa[x] ? x : fa[x] = Find(fa[x]);}
    int dir[][2] = {1,0,0,1,-1,0,0,-1};
    stack<int>s;
    int main()
    {
        int n, m, q, tot = 0, x1, y1, x2, y2;
        scanf("%d%d%d", &n, &m, &q);
        for(int i = 1; i <= n; i++)for(int j = 1; j <= m; j++){ID[i][j] = ++tot; fa[tot] = tot;}
        for(int i = 1; i <= q; i++)
        {
            scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
            c[i] = node(x1, y1, x2, y2);
            for(int x = x1; x <= x2; x++)for(int y = y1; y <= y2; y++)a[x][y]++;
        }
        int white = 0, cnt = 0;
        for(int i = 1; i <= n; i++)for(int j = 1; j <= m; j++)if(!a[i][j])
        {
            white++;
            for(int k = 0; k < 4; k++)
            {
                int x = i + dir[k][0], y = j + dir[k][1];
                if(x >= 1 && x <= n && y >= 1 && y <= m && !a[x][y])
                {
                    int u = ID[i][j], v = ID[x][y];
                    u = Find(u);v = Find(v);
                    if(u != v)fa[u] = v, cnt++;
                }
            }
        }
        s.push(white - cnt);
        for(int i = q; i >= 2; i--)
        {
            for(int x = c[i].x1; x <= c[i].x2; x++)
                for(int y = c[i].y1; y <= c[i].y2; y++)
            {
                a[x][y]--;
                if(!a[x][y])
                {
                    white++;
                    for(int k = 0; k < 4; k++)
                    {
                        int xx = x + dir[k][0], yy = y + dir[k][1];
                        if(xx >= 1 && xx <= n && yy >= 1 && yy <= m && !a[xx][yy])
                        {
                            int u = ID[x][y], v = ID[xx][yy];
                            u = Find(u);v = Find(v);
                            if(u != v)fa[u] = v, cnt++;
                        }
                    }
                }
            }
            s.push(white - cnt);
        }
        while(!s.empty()){cout<<s.top()<<endl;s.pop();}
        return 0;
    }
    View Code

    C .Card Hand Sorting

    pro:给定N张扑克牌,保证来自一副牌,有四种花色。现在让你重排,同种花色放一起,内部递增或者递减。 重排的方式是抽出一张牌,插入到某位置。

    sol:四种花色,枚举花色的排列,再枚举每种花色内是递增还是递减。  对于每种方案,ans=N-LIS。

    (写个结构体还是蛮方便的。

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    map<char, int>level_num, level_color;
    struct node
    {
        char num, color;
        node(){}
        node(char num, char color):num(num), color(color){}
        bool operator <(const node& now)const
        {
            if(level_color[color] == level_color[now.color])//花色相同
            {
                //奇数递增,偶数递减
                if(level_color[color] & 1)return level_num[num] < level_num[now.num];
                else return level_num[num] > level_num[now.num];
            }
            return level_color[color] < level_color[now.color];
        }
        bool operator == (const node& now)const{return num == now.num && color == now.color;}
    }a[110], b[110];
    int dp[60][60], n;
    int solve()
    {
        memset(dp, 0, sizeof(dp));
        for(int i = 1; i <= n; i++)
        {
            for(int j = 1; j <= n; j++)
            {
                dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
                if(a[i] == b[j])dp[i][j] = max(dp[i][j], dp[i - 1][j - 1] + 1);
            }
        }
        return n - dp[n][n];
    }
    char s[] = "shdc";
    int c[5];
    int main()
    {
        int tot = 0;
        for(char i = '2'; i <= '9'; i++)level_num[i] = ++tot;
        level_num['T'] = ++tot;level_num['J'] = ++tot;level_num['Q'] = ++tot;
        level_num['K'] = ++tot;level_num['A'] = ++tot;
        cin >> n;
        for(int i = 1; i <= n; i++){cin >> a[i].num >> a[i].color;b[i] = a[i];}
        for(int i = 1; i <= 4; i++)c[i] = i;
        int ans = n;
        do
        {
            for(int i = 1; i <= 4; i++)level_color[s[i - 1]] = c[i];
            for(int i = 0; i < (1 << 4); i++)
            {
                for(int j = 0; j < 4; j++)
                {
                    level_color[s[j]] *= 2;
                    if(i & (1 << j))level_color[s[j]]++;
                }
                sort(b + 1, b + 1 + n);
                ans = min(ans, solve());
            }
        }while(next_permutation(c + 1, c + 5));
        cout<<ans<<endl;
        return 0;
    }
    View Code

    D .Daydreaming Stockbroker

    pro:开始你有100元,给出N天的股价单价,你每天可以选择用当时的价格交易。限制持有股份不超过100000, 问最后有多少钱。N<365;

    sol:枚举之前哪天买即可。

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=200010;
    ll a[maxn],dp[maxn],ans=100;
    int main()
    {
        int N;
        scanf("%d",&N);
        rep(i,1,N) scanf("%lld",&a[i]);
        dp[1]=dp[2]=100;
        rep(i,2,N){
            rep(j,1,i-1){
               ll t=min(dp[j]/a[j],100000LL);
               dp[i]=max(t*a[i]+dp[j]-t*a[j],dp[i]);
            }
            ans=max(ans,dp[i]);
            dp[i+1]=max(dp[i+1],dp[i]);
        }
        printf("%lld
    ",ans);
        return 0;
    }
    View Code

    E .Exponial

    pro:给定N,M。求。N^((N-1)^(N-2)...)%M;(N,M<1e9)

    sol:显然欧拉降幂。 注意幂>mod时才能降幂,4以内的小于1e9,所以特判。

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    int n,m;
    int phi(int x){
        int ans=x;
        for(int i=2;i*i<=x;i++)
            if(x%i==0){
                ans/=i;ans*=i-1;
                while(x%i==0) x/=i;
        }
        //cout<<x<<" "<<ans<<" "<<endl;;
        if(x>1) ans/=x,ans*=x-1;
        return ans;
    }
    int ksm(int x,int y,int p){
        int ans=1;
        for(;y;y>>=1){
            if(y&1)ans=(ll)ans*x%p;
            x=(ll)x*x%p;
        }
        return ans;
    }
    int dfs(int x,int y){
        if(y==1) return 0;
        if(x==1) return 1;
        if(x==5) return ksm(x,262144,y);
        if(x==4) return ksm(x,9,y);
        if(x==3) return ksm(x,2,y);
        if(x==2) return x%y;
    
        int ph=phi(y);
        return ksm(x,dfs(x-1,ph)+ph,y);
    }
    int main(){
        scanf("%d%d",&n,&m);
        printf("%d",dfs(n,m));
        return 0;
    }
    View Code

    G .Game Rank

    排位模拟题。

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    int n,lev=25,st,wins;
    char s[10010];
    int main(){
        scanf("%s",s+1);
        n=strlen(s+1);
        for(int i=1;i<=n;i++){
            if(s[i]=='W'){
                if(lev>=6&&wins>=2)st+=2,wins++;
                else st++,wins++;
                while(lev>20&&st>2)lev--,st-=2;
                while(lev>15&&st>3)lev--,st-=3;
                while(lev>10&&st>4)lev--,st-=4;
                while(st>5)lev--,st-=5;
            }
            else{
                wins=0;
                if(lev<=20)st--;
                if(st<0){
                    lev++;
                    if(lev>20)lev=20,st=0;
                    else if(lev>15)st=2;
                    else if(lev>10)st=3;
                    else st=4;
                }
            }
            if(lev<=0)return 0*puts("Legend");
        }
        printf("%d",lev);
        return 0;
    }
    View Code

    H .Highest Tower

    pro:BZOJ4886

    小Q正在玩一个叠塔的游戏,游戏的目标是叠出尽可能高的塔。在游戏中,一共有n张矩形卡片,其中第i张卡片的
    长度为a_i,宽度为b_i。小Q需要把所有卡片按一定顺序叠成一座塔,要求对于任意一个矩形,它的长度要严格大
    于它上边的任意一个矩形的长度。塔的高度为所有矩形的宽度之和。在游戏中,小Q可以将卡片翻转90度来使用,
    而且必须用上全部n张卡片。请写一个程序,帮助计算小Q能叠出最高的塔的高度。

    sol:定向问题。 不难证明最后是一棵或者多棵树或者环套树。 证明https://blog.csdn.net/V5ZSQ/article/details/79337446?utm_source=blogxgwz8

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=2000101;
    map<int,int>mp;
    int ind[maxn],tot,mx[maxn],fa[maxn],tag[maxn],val[maxn]; ll ans;
    int find(int x){
        if(x==fa[x]) return x;
        return fa[x]=find(fa[x]);
    }
    int u[maxn],v[maxn];
    int main()
    {
        int N,x,y;
        scanf("%d",&N);
        rep(i,1,N){
            scanf("%d%d",&u[i],&v[i]);
            x=u[i]; y=v[i];
            if(!mp[x]) mp[x]=++tot,val[tot]=mx[tot]=x;
            if(!mp[y]) mp[y]=++tot,val[tot]=mx[tot]=y;
            x=u[i]=mp[x]; y=v[i]=mp[y];
            ind[x]++; ind[y]++;
        }
        rep(i,1,tot) fa[i]=i;
        rep(i,1,tot){
            x=find(u[i]); y=find(v[i]);
            if(tag[x]&&tag[y]) continue;
            if(x==y) tag[y]=1;
            else fa[x]=y,tag[y]|=tag[x],mx[y]=max(mx[x],mx[y]);
        }
        rep(i,1,tot){
            ans+=1LL*(ind[i]-1)*val[i];
            if(find(i)==i&&!tag[i]) ans+=mx[i];
        }
        printf("%lld
    ",ans);
        return 0;
    }
    View Code

    J .Jumbled Compass

    模拟。

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=200010;
    int main()
    {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=0;i<=180;i++){
            if((n+i)%360==m)return 0*printf("%d",i);
            if((n-i+360)%360==m)return 0*printf("%d",-i);
        }
    }
    View Code

    K .Keeping the Dogs Apart

    题意: 给定两支猫的行走路线, 都是直线行走, 求他们都在走的最近距离.

    思路: 模拟即可. 每次得到min{到转折点的时间},  然后得到结束位置, 至于这个过程的最近距离,我们可以假设一个不动,那么就是点到线段的距离. 继续模拟.

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=200010;
    double x[maxn][2],y[maxn][2],ans;
    const double inf=1e200;
    const double pi=4*atan(1.0);
    struct point{
        double x,y;
        point(double a=0,double b=0):x(a),y(b){}
    };
    int dcmp(double x){ return fabs(x)<0.0000000000001?0:(x<0?-1:1);}
    point operator +(point A,point B) { return point(A.x+B.x,A.y+B.y);}
    point operator -(point A,point B) { return point(A.x-B.x,A.y-B.y);}
    point operator *(point A,double p){ return point(A.x*p,A.y*p);}
    point operator /(point A,double p){ return point(A.x/p,A.y/p);}
    point rotate(point A,double rad){
        return point(A.x*cos(rad)-A.y*sin(rad), A.x*sin(rad)+A.y*cos(rad));
    }
    bool operator ==(const point& a,const point& b) {
         return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;
    }
    double dot(point A,point B){ return A.x*B.x+A.y*B.y;}
    double det(point A,point B){ return A.x*B.y-A.y*B.x;}
    double dot(point O,point A,point B){ return dot(A-O,B-O);}
    double det(point O,point A,point B){ return det(A-O,B-O);}
    double length(point A){ return sqrt(dot(A,A));}
    double angle(point A,point B){ return acos(dot(A,B)/length(A)/length(B));}
    bool isPointOnSegment(point p,point a1,point a2)
    {
        //点是否在线段上
        return dcmp(det(a1-p,a2-p)==0&&dcmp(dot(a1-p,a2-p))<=0);
    }
    double distoseg(point P,point A,point B)
    {
        if(isPointOnSegment(P,A,B)) return 0.0;
        //点到线段距离
        if(A==B) return length(P-A);
        point v1=B-A,v2=P-A,v3=P-B;
        if(dcmp(dot(v1,v2))<0) return length(v2);
        else if(dcmp(dot(v1,v3))>0) return length(v3);
        return fabs(det(v1,v2)/length(v1));
    }
    double dist(double x1,double y1,double x2,double y2)
    {
        return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
    }
    void solve(int A,int B,double t)
    {
        double dx[2],dy[2];
        double d1=dist(x[A][0],y[A][0],x[A+1][0],y[A+1][0]);
        double d2=dist(x[B][1],y[B][1],x[B+1][1],y[B+1][1]);
        dx[0]=(x[A+1][0]-x[A][0])/d1; dy[0]=(y[A+1][0]-y[A][0])/d1;
        dx[1]=(x[B+1][1]-x[B][1])/d2; dy[1]=(y[B+1][1]-y[B][1])/d2;
        double sx=x[A][0],sy=y[A][0],tx=x[A][0]+(dx[0]-dx[1])*t,ty=y[A][0]+(dy[0]-dy[1])*t;
        double res=distoseg(point(x[B][1],y[B][1]),point(sx,sy),point(tx,ty));
        ans=min(ans,res);
        x[A][0]+=dx[0]*t; y[A][0]+=dy[0]*t;
        x[B][1]+=dx[1]*t; y[B][1]+=dy[1]*t;
    }
    int main()
    {
        int N,M;
        scanf("%d",&N);
        rep(i,1,N) scanf("%lf%lf",&x[i][0],&y[i][0]);
        scanf("%d",&M);
        rep(i,1,M) scanf("%lf%lf",&x[i][1],&y[i][1]);
        ans=110000000000;
        int A=1,B=1;
        while(A<N&&B<M){
            double da=dist(x[A][0],y[A][0],x[A+1][0],y[A+1][0]);
            double db=dist(x[B][1],y[B][1],x[B+1][1],y[B+1][1]);
            if(da<db){
                solve(A,B,da);
                A++;
            }
            else if(da==db){
                solve(A,B,da);
                A++; B++;
            }
            else {
                solve(A,B,db);
                B++;
            }
        }
        printf("%.8lf
    ",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    好书推介《实战机器学*》
    Web技术图书名单
    大数据技术书,看看有没有感兴趣的
    博客园设置自定义皮肤,添加自定义小模块悬浮天气组件,github图标链接等
    Final Cut Pro 视频剪辑学习记录,快捷操作等
    css 利用 clip-path 裁剪多边形,三角形,梯形,六边形等
    有呀,有呀,设计!有呀,有呀,组件!
    github README添加badge标识,多彩的tag标签
    vue timeline 开箱即用的时间轴组件,日志更新时间轴组件
    那些需要收藏的网站网址
  • 原文地址:https://www.cnblogs.com/hua-dong/p/10656666.html
Copyright © 2011-2022 走看看