zoukankan      html  css  js  c++  java
  • Gym

    -------------------题目难度较难,但挺有营养的。慢慢补。

    A .ASCII Addition

    pro:用一定的形式表示1到9,让你计算加法。

    sol:模拟。 

    solved by fzl;

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=2000010;
    typedef long long ll;
    string s[11] =
    {
        "xxxxxx...xx...xx...xx...xx...xxxxxx",
        "....x....x....x....x....x....x....x",
        "xxxxx....x....xxxxxxx....x....xxxxx",
        "xxxxx....x....xxxxxx....x....xxxxxx",
        "x...xx...xx...xxxxxx....x....x....x",
        "xxxxxx....x....xxxxx....x....xxxxxx",
        "xxxxxx....x....xxxxxx...xx...xxxxxx",
        "xxxxx....x....x....x....x....x....x",
        "xxxxxx...xx...xxxxxxx...xx...xxxxxx",
        "xxxxxx...xx...xxxxxx....x....xxxxxx",
        ".......x....x..xxxxx..x....x......."
    };
    char Map[10][1000];
    int judge(int x)
    {
        string tmp;
        for(int i = 0; i < 7; i++)
            for(int j = x; j < x + 5; j++)tmp += Map[i][j];
        for(int i = 0; i <= 10; i++)if(s[i] == tmp)return i;
    }
    int main()
    {
        for(int i = 0; i < 7; i++)cin >> Map[i];
        int n = strlen(Map[0]);
        ll cnt = 0, a;
        for(int i = 0; i < n; i += 6)
        {
            int tmp = judge(i);
            if(tmp == 10){a = cnt;cnt = 0;continue;}
            cnt = cnt * 10 + tmp;
        }
        a = a + cnt;
        stringstream ss;string tmp;
        ss << a;
        ss >> tmp;
        for(int i = 0; i < 7; i++)for(int j = 0; j < tmp.size(); j++)
        {
            for(int k = 5 * i; k < 5 * i + 5; k++)cout<<s[tmp[j] - '0'][k];
            if(j == tmp.size() - 1)cout<<endl;
            else cout<<".";
        }
        return 0;
    }
    View Code

    B .Book Borders

    pro:给定文本,假设每行最多放L个字母时,统计第一行的信息。

    sol:模拟+二分即可。

    solve by pb。

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    string s[500010];
    int a,b,cnt,ans,n,sum[500010]; 
    template<class T>
    inline void read(T&a){
        char c=getchar();
        for(a=0;(c<'0'||c>'9')&&c!='-';c=getchar());
        bool f=0;if(c=='-')f=1,c=getchar();
        for(;c>='0'&&c<='9';c=getchar())a=a*10+c-'0';
        if(f)a=-a;
    }
    int main(){
        ios::sync_with_stdio(false);
        while(cin.peek()!='
    ')cin>>s[++n],sum[n]=sum[n-1]+s[n].size();
        cin>>a>>b;
        for(int i=a;i<=b;i++){
            int las=0,mid,l,r,now,hang=0;
            ans=0;
            while(las<n){
                l=las+1,r=n;
                while(l<=r){
                    mid=(l+r)>>1;
                    if(sum[mid]-sum[las]+mid-las-1<=i)now=mid,l=mid+1;
                    else r=mid-1;
                }
                ans+=s[las+1].size();
                las=now;hang++;
            }
            printf("%d
    ",ans+hang-1);
        }
        return 0;
    }
    View Code

    D .Digit Division

    pro:给定一个数字串,让你切割,使得切割后的每一部分都是M的倍数。

    sol:保存前面切割的方案数,dp即可。 没mod 1e9+7,wa了一发。

    solve by fcy。

    #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=2000010;
    const int Mod=1e9+7;;
    ll ans,mp; char c[maxn];
    int main()
    {
        mp=1;
        int N,M,x=0;
        scanf("%d%d%s",&N,&M,c+1);
        rep(i,1,N){
            x=x*10+c[i]-'0'; x%=M;
            if(x==0) ans=mp,(mp+=mp)%=Mod;
            else ans=0;
        }
        printf("%lld
    ",ans%Mod);
        return 0;
    }
    View Code

    F.Frightful Formula

    pro:给定N*N矩阵,给出第一行第一列的初始值 f[i][1]和f[1][i],其他位置的满足f[i][j]=a*f[i][j-1]+b*f[i-1][j]+c;  求f[N][N];

    sol:如果没有c,此题直接组合数可以做,但是有c,可能要fft或者其他多项式的算法。 比较麻烦。

    我们可以想办法把c去掉,不过数学渣fcy好像不会,只能参考别人的。 待定系数法很好的解决了这个问题。

    参考:https://blog.csdn.net/liufengwei1/article/details/78271574

    H .Hovering Hornet

    pro:三维平面里,给定一个5*5*5的立方体,内部含有一个1*1*1的骰子,现在有一只蜜蜂,问它看到的点数和的期望。

    sol:由于二者都是处于水平位置,所以看到上面的点的概率是一定的。 而周围4个点的概率取决于底面的面积,直接用半平面交即可。

    updated by fcy。

    #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=10010;
    const double eps=1e-8;
    struct point{
        double x,y;
        point(){}
        point(double xx,double yy):x(xx),y(yy){}
    };
    struct line{
        point a;//起点
        point p;//起点到终点的向量
        line(){}
        line(point aa,point pp):a(aa),p(pp){}
        double angle;
    };
    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;}
    point operator *(point A,double p){ return point(A.x*p,A.y*p);}
    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);}
    double getangle(point a){ return atan2(a.y,a.x);}
    double getangle(line a){ return getangle(a.p);}
    point llintersect(line A,line B)
    {
        point C=A.a-B.a;
        double t=det(C,B.p)/det(B.p,A.p);
        return A.a+A.p*t;
    }
    point s[maxn]; line t[maxn],q[maxn]; int head,tail;
    bool cmp(line a,line b){
        double A=getangle(a),B=getangle(b);
        point t=(b.a+b.p)-a.a;
        if(fabs(A-B)<eps) return det(a.p,t)>0.0;
        return A<B;
    }
    bool onright(line P,line a,line b)
    {
        point o=llintersect(a,b);
        point Q=o-P.a;
        return det(Q,P.p)>0; //如果同一直线上不能相互看到,则>=0
    }
    point w[maxn]; int pcnt=0;
    double halfplaneintersect(int N,line p)
    {
        s[N+1]=s[1];
        rep(i,1,N) t[i].a=s[i],t[i].p=s[i+1]-s[i];
        t[++N]=p;
        sort(t+1,t+N+1,cmp);
        int tot=0;
        rep(i,1,N-1) {
            if(fabs(getangle(t[i])-getangle(t[i+1]))>eps)
              t[++tot]=t[i];
        }
        t[++tot]=t[N]; head=tail=0;
        rep(i,1,tot){
            while(tail>head+1&&onright(t[i],q[tail],q[tail-1])) tail--;
            while(tail>head+1&&onright(t[i],q[head+1],q[head+2])) head++;
            q[++tail]=t[i];
        }
        while(tail>head+1&&onright(t[head+1],q[tail],q[tail-1])) tail--;
        //while(tail>head+1&&onright(t[tail],q[head+1],q[head+2])) head++;加上了会wa6,不知道为什么
        pcnt=0; q[tail+1]=q[head+1];
        rep(i,head+1,tail)  w[++pcnt]=llintersect(q[i],q[i+1]);
        double res=0;
        rep(i,2,pcnt-1) res+=det(w[i]-w[1],w[i+1]-w[1]);
        return res/2;
    }
    void solve()
    {
        double ans=0,area=5.0*5*5-1*1*1;
        rep(i,1,4) scanf("%lf%lf",&s[i].x,&s[i].y);
        ans+=6.0*halfplaneintersect(4,line(point(-0.5,0.5),point(1,0)))*5/area;
        ans+=5.0*5*5*4/area;
        ans+=4.0*halfplaneintersect(4,line(point(-0.5,-0.5),point(0,1)))*5/area;
        ans+=3.0*halfplaneintersect(4,line(point(0.5,0.5),point(0,-1)))*5/area;
        ans+=1.0*halfplaneintersect(4,line(point(0.5,-0.5),point(-1,0)))*5/area;
        printf("%.10lf
    ",ans);
    }
    int main()
    {
        solve();
        return 0;
    }
    View Code

    I .Ice Igloos

    pro:在500*500的二维平面上,给定N个圆。Q次询问,每次给出一个线段,问多少个圆和直线有交点。 N,Q<1e5

    sol:由于平面并不大,所以我们可以暴力一点的做法。 即去找可能有交点是位置,然后看那个位置上的圆是否满足。

    solved by fcy 我的做法是,枚举x坐标,然后求出这个x到直线最近的点,然后往两边找,复杂度~500*Q*常数。(比标程暴力一丢丢)

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=2000010;
    double G[510][510];
    struct point{
        double x,y;
        point(){}
        point(double xx,double yy):x(xx),y(yy){}
    }A,B;
    double det(point a,point b) {return a.x*b.y-a.y*b.x;}
    double dot(point a,point b) {return a.x*b.x+a.y*b.y;}
    double dist(point a,point b){
        return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
    }
    double ptoseg(point p)
    {
        point Ap=point(p.x-A.x,p.y-A.y);
        point AB=point(B.x-A.x,B.y-A.y);
        point pB=point(B.x-p.x,B.y-p.y);
        if(dot(AB,Ap)<=0) return dist(A,p);
        if(dot(AB,pB)<=0) return dist(B,p);
        return fabs(det(Ap,AB)/dist(A,B));
    }
    int ans;
    void get1(int x,int y)
    {
        while(y>=1){
            double ty=1.0*y;
            double dis=ptoseg(point(1.0*x,ty));
            if(dis>1.0) break;
            if(G[x][y]>dis) ans++;
            y--;
        }
    }
    void get2(int x,int y)
    {
        while(y<=500){
            double ty=1.0*y;
            double dis=ptoseg(point(1.0*x,ty));
            if(dis>1.0) break;
            if(G[x][y]>dis) ans++;
            y++;
        }
    }
    int main()
    {
        int N,Q;
        scanf("%d",&N);
        rep(i,1,N){
             int x,y; double r;
             scanf("%d%d%lf",&x,&y,&r);
             G[x][y]=r;
        }
        scanf("%d",&Q);
        while(Q--){
            scanf("%lf%lf%lf%lf",&A.x,&A.y,&B.x,&B.y);
            if(A.x>B.x||(A.x==B.x&&A.y>B.y)) swap(A.x,B.x),swap(A.y,B.y); ans=0;
            if(A.x==B.x){
                 for(int i=(int)A.y;i<=(int)B.y;i++)
                    ans+=(G[(int)A.x][i]>0);
            }
            else if(A.y==B.y){
                for(int i=(int)A.x;i<=(int)B.x;i++)
                    ans+=(G[i][(int)A.y]>0);
            }
            else {
                for(int i=max((int)A.x-1,1);i<=min((int)B.x+1,500);i+=1){
                   double y=1.0*A.y;
                   if(i!=A.x) y=A.y+1.0*(B.y-A.y)/(B.x-A.x)*(i-A.x);
                   int t=(int)y;
                   get1(i,t);
                   get2(i,t+1);
                }
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code

    J .Juice Junctions

    pro:给定N点M边的无向图,保证没个点的度数不超过3。 现在求所有点对的最大流。N<3e3, M<4.5e3;

    sol:开始以为是N*M的复杂度,枚举起点,然后dfs,发现由于方向不能确定,所有并不能实现。

    updated by fcy。

    由于度数<=3;所以我们枚举点对,然后去验证可能性(0,1,2,3)。

    0:不连通;    1:连通;   2: 双连通; 3:删去任意一边任然是双连通。

    0,1用并查集可以做; 2用tarjan做。 3的话,需要用点东西才行,std的做法是,枚举删去的边,然后保存所有点所在的scc,所以两个点的所有情况下scc都同,即满足,这里可以用hash做。

    #include<bits/stdc++.h>
    #define ll unsigned long long
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=100010;
    const int seed1=131;
    const int seed2=1331;
    int Laxt[maxn],Next[maxn],To[maxn],cnt=1;
    int q[maxn],top,dfn[maxn],low[maxn],scc[maxn],scc_cnt,times;
    int fa[maxn],ans,del,hash1[maxn],hash2[maxn];
    void add(int u,int v)
    {
        Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v;
    }
    int find(int x)
    {
        if(x==fa[x]) return x;
        return fa[x]=find(fa[x]);
    }
    void dfs(int u,int f)
    {
        q[++top]=u; dfn[u]=low[u]=++times;
        for(int i=Laxt[u];i;i=Next[i]){
            if(i==del*2||i==del*2+1||To[i]==f) continue;
            if(!dfn[To[i]]) {
                dfs(To[i],u);
                low[u]=min(low[u],low[To[i]]);
            }
            else low[u]=min(low[u],dfn[To[i]]);
        }
        if(dfn[u]==low[u]){
            scc_cnt++;
            while(1){
                int x=q[top--];
                scc[x]=scc_cnt;
                if(x==u) break;
            }
        }
    }
    int main()
    {
        int N,M,u,v;
        scanf("%d%d",&N,&M);
        rep(i,1,N) fa[i]=i;
        rep(i,1,M){
            scanf("%d%d",&u,&v);
            fa[find(u)]=find(v);
            add(u,v); add(v,u);
        }
        rep(i,1,N)
         rep(j,i+1,N)
          if(find(i)==find(j)) ans++;
    
        rep(i,1,N)
          if(!dfn[i]) dfs(i,0);
    
        rep(i,1,N)
         rep(j,i+1,N)
          if(scc[i]==scc[j]) ans++;
    
        rep(i,1,M) {
            del=i; scc_cnt=0; times=0;
            rep(j,1,N) dfn[j]=scc[j]=0;
            rep(j,1,N) if(!dfn[j]) dfs(j,0);
            rep(j,1,N){
                hash1[j]=hash1[j]*seed1+scc[j];
                hash2[j]=hash2[j]*seed2+scc[j];
            }
        }
        rep(i,1,N)
         rep(j,i+1,N) if(hash1[i]==hash1[j]&&hash2[i]==hash2[j]) ans++;
        printf("%d
    ",ans);
        return 0;
    }
    View Code

    K .Kernel Knights

    pro:给定二分图。每个点有个出度,现在让你找一种方案,选出其中一些点S,满足这些点之间没有边,而未选的点,至少有S中的点指向它,保证有解。

    sol:首先,如果一个点没有入度,必选。 我们可以用topo排序得到这些点。 对于剩下的点,由于是二分图,我们选择其中一边即可。

    solve by fzl&pb

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=2000010;
    typedef long long ll;
    int n,a[200010],du[200010];
    queue<int>que;
    bool s[200010],c[200010];
    void dfs(int x,int y){
        if(y){
            c[x]=1;
            if(!s[a[x]]&&!c[a[x]])dfs(a[x],0);
        }
        else{
            s[x]=1;
            if(!s[a[x]]&&!c[a[x]])dfs(a[x],1);
        }
    }
    int main(){
        //freopen("1.in", "r", stdin);
        //freopen("1.out", "w", stdout);
        scanf("%d",&n);
        for(int i=1;i<=2*n;i++){
            scanf("%d",a+i);
            du[a[i]]++;
        }
        for(int i=1;i<=2*n;i++)
            if(!du[i])que.push(i);
        while(!que.empty()){
            int x=que.front();que.pop();
            //cout<<x<<" "<<c[x]<<endl;
            if(c[x])continue;du[a[x]]--;
            s[x]=1;
            if(!c[a[x]])c[a[x]]=1,du[a[a[x]]]--;
            if(!s[a[a[x]]] && !c[a[a[x]]] && !du[a[a[x]]])que.push(a[a[x]]);
        }
        for(int i=1;i<=2*n;i++)
            if(!s[i]&&!c[i])dfs(i,0);
        for(int i=1;i<=2*n;i++)
            if(s[i])printf("%d ",i);
        return 0;
    }
    View Code
  • 相关阅读:
    [BJOI2019] 光线
    C# 从零开始写 SharpDx 应用 笔刷
    BAT 脚本判断当前系统是 x86 还是 x64 系统
    BAT 脚本判断当前系统是 x86 还是 x64 系统
    win2d 通过 CanvasActiveLayer 画出透明度和裁剪
    win2d 通过 CanvasActiveLayer 画出透明度和裁剪
    PowerShell 拿到显卡信息
    PowerShell 拿到显卡信息
    win10 uwp 如何使用DataTemplate
    win10 uwp 如何使用DataTemplate
  • 原文地址:https://www.cnblogs.com/hua-dong/p/10671298.html
Copyright © 2011-2022 走看看