zoukankan      html  css  js  c++  java
  • Gym101485: NWERC 2015(队内第6次训练)

    A .Assigning Workstations

    题意:给定N个人的工作时间和工作时长,我们可以假设有无数台工作机器,如果一台机器超过M时间未使用就会关闭,那么我们怎么安排机器的使用,使得需要开启机器的次数最少。

    思路:贪心,维护一个时间队列q,维护一个单调队列q1; 前者表示没有使用了但还没关闭的机器队列,后者表示还在使用的机器。   那么我们每次把已经使用完的加入q,如果关闭了或者被新的人使用了就移除。 使用的新机器加入q1....

    #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 = 3e5 + 10;
    struct node
    {
        ll a, s;
        bool operator < (const node& b)const{
            return a < b.a || a == b.a && s < b.s;
        }
    }a[maxn];
    int ans; ll n, m;
    queue<int>q;
    priority_queue<int>q1;
    int main()
    {
        scanf("%lld%lld", &n, &m);
        for(int i = 1; i <= n; i++)
            scanf("%lld%lld", &a[i].a, &a[i].s);
        sort(a + 1, a + 1 + n);
        for(int i = 1; i <= n; i++)
        {
            while(!q1.empty())
                if(-q1.top() <= a[i].a)q.push(-q1.top()+m),q1.pop();
                else break;
            while(!q.empty()&&q.front()<a[i].a)q.pop();
            if(!q.empty())q1.push(-a[i].a-a[i].s),q.pop();
            else ans++,q1.push(-a[i].a-a[i].s);
        }
        printf("%d",n-ans);
        return 0;
    }
    View Code

    B .Better Productivity

    题意:给出N个人,现在让你分P组,每组的工作效率是最小结束时间-最大开始时间,要求每一组的效率的正数,求最大效率和。

    思路: 把包含至少一个其他的分到A组;否则到B组。  

                A组的要么单独分到一组,要么和它包含的某一个在一组(可以反证,假设已经分好组了,现在把不是单独分组的A加进去,如果分到不是包含关系的里面去,只会把答案变小)。   

               分组可以用栈进行。 而不是N^2枚举,因为多个相同的时候我们可以要保留一个作为最小的一个分到B组。

                然后,现在A里面的没有包含关系了,我们可以排序,排序后一定是相邻的分到同一组,这里DP即可。         

               枚举单独分组的A,加上dp[][]跟新最大值即可。 dp[i][j]表示前i个人分j组的最大效率和; mp[i][j]表示i到j的人分一组的效率。

    (这种题一看就是排序,毕竟交集肯定是相邻的在一起最大,然后DP或者线段树啥的。但是这里按照左端点和右端点呢,显然在有包含关系的时候都不行,所以要去掉包含关系,比赛的时候想到这里了,然后就没思路了。 关键在于想到A组的人如果不单独分组的话,他可以分到合理的组,使得答案不减小。

    #include<bits/stdc++.h>
    #define pii pair<int,int>
    #define ll long long
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=210;
    pii a[maxn];int tot,cnt,ans;
    int vis[maxn],dp[maxn][maxn],len[maxn],mp[maxn][maxn];
    int main()
    {
        int N,P;
        scanf("%d%d",&N,&P);
        rep(i,1,N) scanf("%d%d",&a[i].first,&a[i].second);
        sort(a+1,a+N+1);
        rep(i,1,N)
         rep(j,i+1,N)
           if(a[i].second>=a[j].second){ vis[i]=1; break;}
        rep(i,1,N)
          if(vis[i]) len[++tot]=a[i].second-a[i].first;
          else a[++cnt]=a[i];
        sort(len+1,len+tot+1); reverse(len+1,len+tot+1);
        rep(i,1,tot) len[i]+=len[i-1];
    
        rep(i,1,cnt){
           int Mx=a[i].second,Mn=a[i].first;
           rep(j,i,cnt){
              Mx=min(Mx,a[j].second),Mn=max(Mn,a[j].first);
              mp[i][j]=Mx-Mn;
           }
        }
    
        memset(dp,-1,sizeof(dp)); dp[0][0]=0;
        rep(i,1,min(cnt,P))
         rep(j,1,cnt)
          rep(k,0,j-1) {
            if(mp[k+1][j]>0&&dp[k][i-1]!=-1)
             dp[j][i]=max(dp[j][i],dp[k][i-1]+mp[k+1][j]);
        }
    
        rep(i,max(P-cnt,0),tot){
            if(dp[cnt][P-i]>0)
            ans=max(ans,len[i]+dp[cnt][P-i]);
        }
    
        printf("%d
    ",ans);
        return 0;
    }
    View Code

    C .Cleaning Pipes

    #include<bits/stdc++.h>
    #define pii pair<int,int>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const double eps = 1e-10;
    const double pi = 3.1415926535897 ;
    struct Point
    {
        double x, y;
        Point(double x = 0, double y = 0):x(x), y(y){}
    };
    typedef Point Vector;
    Vector operator + (Vector A, Vector B){return Vector(A.x+B.x, A.y+B.y);}//向量+向量=向量;点+向量=向量
    Vector operator - (Vector A, Vector B){return Vector(A.x-B.x, A.y-B.y);}//点-点=向量
    bool operator < (const Point& a, const Point& b)
    {
        return a.x < b.x || (a.x == b.x && a.y < b.y);
    }
    int dcmp(double x)//三态函数,高精度判断
    {
        if(fabs(x) < eps)return 0; else return x < 0 ? -1 : 1;
    }
    bool operator == (const Point& a, const Point& b)
    {
        return dcmp(a.x-b.x) == 0 && dcmp(a.y-b.y) == 0;
    }
    double Cross(Vector A, Vector B){return A.x*B.y - A.y*B.x;}//叉积
    bool SegmentProperIntersection(Point a1, Point a2, Point b1, Point b2)
    //判断线段a1a2和b1b2是否规范相交(在端点处相交得用下一个函数特殊判断)
    {
        double c1 = Cross(a2-a1, b1-a1), c2 = Cross(a2-a1, b2-a1),
               c3 = Cross(b2-b1, a1-b1), c4 = Cross(b2-b1, a2-b1);
        return dcmp(c1) * dcmp(c2) < 0 && dcmp(c3) * dcmp(c4) < 0;
    }
    Point a[1010];
    int c[1010];
    Point b[1010];
    bool judge(int i, int j)//如果i和j相交,且交点不为两个线段的起点
    {
        if(b[i] == b[j])return true;
        if(a[c[i]] == a[c[j]] || a[c[i]] == b[j] || b[i] == a[c[j]])return false;
        return SegmentProperIntersection(a[c[i]],b[i],a[c[j]],b[j]);
    }
    
    int color[1010];//0表示未染色 1表示白色 2表示黑色
    vector<int>G[1010];
    bool bipartite(int u)
    {
        for(int i = 0; i < G[u].size(); i++)
        {
            int v = G[u][i];
            if(color[u] == color[v])return false;//u v颜色一样
            if(!color[v])
            {
                color[v] = 3 - color[u];//节点u与v染不同的颜色
                if(!bipartite(v))return false;
            }
        }
        return true;
    }
    int main(){
        int n, m;
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; i++)scanf("%lf%lf", &a[i].x, &a[i].y);
        for(int i = 1; i <= m; i++)
            scanf("%d%lf%lf", &c[i], &b[i].x, &b[i].y);
        for(int i = 1; i <= m; i++)
            for(int j = i + 1; j <= m; j++)
                if(judge(i, j))G[i].push_back(j),G[j].push_back(i);
        bool flag = 0;
        for(int i = 1; i <= m; i++)if(!color[i])
        {
            color[i] = 1;
            if(!bipartite(i)){flag = 1;break;}
        }
        if(flag)puts("impossible");
        else puts("possible");
        return 0;
    }
    View Code

    D .Debugging

    题意:题目给N,R,P。表示给出一个一定有一行bug的代码,长度为N,现在让你debug,你可以在某处加一行“输出”,时间是P; 运行一次的时间是R。(输出是表示你可以对比这里的放的答案是否符合预期)。现在稳你用最有策略,最坏情况下的时间。 N<1e6; R,P<1e9

    思路:N很小,所以所有长度的答案都可以算出来,估计就是记忆化了。一开始以为要么是二分,要么用L-1行输出。WA了。然后才去想,还是应该把所有的情况都求出来,长度为L的时候 ,res=min((L+i)/i+R+i*P);我们整数分块即可。

     题目的最坏情况表示:你下一次需要去检验的长度是当前最长的一个区间块,即向上取整,所以我们用(L+i)/i

    #include<bits/stdc++.h>
    #define pii pair<int,int>
    #define ll long long
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=210;
    pii a[maxn];int tot,cnt,ans;
    int vis[maxn],dp[maxn][maxn],len[maxn],mp[maxn][maxn];
    int main()
    {
        int N,P;
        scanf("%d%d",&N,&P);
        rep(i,1,N) scanf("%d%d",&a[i].first,&a[i].second);
        sort(a+1,a+N+1);
        rep(i,1,N)
         rep(j,i+1,N)
           if(a[i].second>=a[j].second){ vis[i]=1; break;}
        rep(i,1,N)
          if(vis[i]) len[++tot]=a[i].second-a[i].first;
          else a[++cnt]=a[i];
        sort(len+1,len+tot+1); reverse(len+1,len+tot+1);
        rep(i,1,tot) len[i]+=len[i-1];
    
        rep(i,1,cnt){
           int Mx=a[i].second,Mn=a[i].first;
           rep(j,i,cnt){
              Mx=min(Mx,a[j].second),Mn=max(Mn,a[j].first);
              mp[i][j]=Mx-Mn;
           }
        }
    
        memset(dp,-1,sizeof(dp)); dp[0][0]=0;
        rep(i,1,min(cnt,P))
         rep(j,1,cnt)
          rep(k,0,j-1) {
            if(mp[k+1][j]>0&&dp[k][i-1]!=-1)
             dp[j][i]=max(dp[j][i],dp[k][i-1]+mp[k+1][j]);
        }
    
        rep(i,max(P-cnt,0),tot){
            if(dp[cnt][P-i]>0)
            ans=max(ans,len[i]+dp[cnt][P-i]);
        }
    
        printf("%d
    ",ans);
        return 0;
    }
    View Code

    E .Elementary Math

    题意:给你一个数 N, 然后下面有 N 对数,每对数可以进行 + - * 操作,每对数选择一个结果,是不是存在每对数选择的结果都不一样。如果是,把每对数选择的结果写下来,并记录下是什么操作,如果不行,就输出 impossible。
    思路:这个题看着就是一个二分图匹配问题,看能否匹配N对。

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    struct edge{
        int d,nex,dat;
    }e[1000000];
    int n,q[10010],d[10010],efree=1,cnt,ans,fh[2510];
    long long x[2510],y[2510],num[10010];char f[5];
    queue<int>que;
    map<long long,int>ma;
    map<long long,int>::iterator ii;
    inline void add(int x,int y,int z){e[++efree]=(edge){y,q[x],z};q[x]=efree;}
    int dfs(int x,int y){
        if(x==cnt+1||!y)return y;
        int now,tot=0;
        for(int i=q[x];i;i=e[i].nex)
            if(d[e[i].d]==d[x]+1&&e[i].dat){
                now=dfs(e[i].d,min(y,e[i].dat));
                e[i].dat-=now;e[i^1].dat+=now;
                tot+=now;if(tot==y)return y;
            }
        if(!tot)d[x]=-1;
        return tot;
    }
    inline bool bfs(){
        memset(d,0,sizeof(d));d[0]=1;
        que.push(0);
        while(!que.empty()){
            int x=que.front();que.pop();
            for(int i=q[x];i;i=e[i].nex)
                if(e[i].dat&&!d[e[i].d])d[e[i].d]=d[x]+1,que.push(e[i].d);
        }
        return d[cnt+1];
    }
    void dfs(int xx){
        for(int i=q[xx];i;i=e[i].nex)
            if(e[i].dat&&e[i].d<=n){
                if(x[e[i].d]+y[e[i].d]==num[xx])fh[e[i].d]=1;
                else if(x[e[i].d]-y[e[i].d]==num[xx])fh[e[i].d]=2;
                else fh[e[i].d]=3;
                return;
            }
    }
    long long ff(long long x,long long y,int z){
        if(z==1)return x+y;
        if(z==2)return x-y;
        return x*y;
    }
    int main(){
        scanf("%d",&n);cnt=n;f[1]='+';f[2]='-';f[3]='*';
        for(int i=1;i<=n;i++){
            add(0,i,1),add(i,0,0);
            scanf("%lld%lld",x+i,y+i);
            long long a=x[i],b=y[i];
            if(!ma[a+b])ma[a+b]=++cnt,num[cnt]=a+b;
            if(!ma[a-b])ma[a-b]=++cnt,num[cnt]=a-b;
            if(!ma[a*b])ma[a*b]=++cnt,num[cnt]=a*b;
            add(i,ma[a+b],1),add(ma[a+b],i,0);
            add(i,ma[a*b],1),add(ma[a*b],i,0);
            add(i,ma[a-b],1),add(ma[a-b],i,0);
        }
        for(ii=ma.begin();ii!=ma.end();ii++)
            add((*ii).second,cnt+1,1),add(cnt+1,(*ii).second,0);
        while(bfs())ans+=dfs(0,2147483647);
        if(ans==n){
            for(int i=q[cnt+1];i;i=e[i].nex)
                if(e[i].dat)dfs(e[i].d);
            for(int i=1;i<=n;i++)printf("%lld %c %lld = %lld
    ",x[i],f[fh[i]],y[i],ff(x[i],y[i],fh[i]));
        }
        else puts("impossible");
        return 0;
    }
    View Code

    G .Guessing Camels

    题意:给定三个N的排列A,B,C;问多少对数字(x,y),在三个排列里x出现的位置在y的前面

    思路:BC按照A标号,然后CDQ分治即可。(这里可以把排序的部分转化为双指针,会快一个log)

    #include<bits/stdc++.h>
    #define pii pair<int,int>
    #define ll long long
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=4000010;
    int a[maxn],b[maxn],c[maxn],pos[maxn];
    ll sum[maxn],ans; int N;
    struct in{
        int id,x,y;
    }s[maxn];
    bool cmp1(in w,in v){ return w.id<v.id;}
    bool cmp2(in w,in v){ return w.x<v.x; }
    void add(int x,int val)
    {
        while(x<=N){
            sum[x]+=val;x+=(-x)&x;
        }
    }
    int query(int x){
        int res=0; while(x){
            res+=sum[x]; x-=(-x)&x;
        } return res;
    }
    void solve(int L,int R)
    {
        if(L>=R) return ;
        int Mid=(L+R)>>1;
        solve(L,Mid);
        sort(s+L,s+R+1,cmp2);
        rep(i,L,R){
            if(s[i].id<=Mid) add(s[i].y,1);
            else ans+=query(s[i].y);
        }
         rep(i,L,R){
            if(s[i].id<=Mid) add(s[i].y,-1);
        }
        sort(s+L,s+R+1,cmp1);
        solve(Mid+1,R);
    }
    int main()
    {
        scanf("%d",&N);
        rep(i,1,N) scanf("%d",&a[i]),pos[a[i]]=i;
        rep(i,1,N) scanf("%d",&b[i]),b[i]=pos[b[i]],s[b[i]].x=i;
        rep(i,1,N) scanf("%d",&c[i]),c[i]=pos[c[i]],s[c[i]].y=i;
        rep(i,1,N) s[i].id=i;
        solve(1,N);
        printf("%lld
    ",ans);
        return 0;
    }
    View Code

    I .Identifying Map Tiles

    递推找位置:

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    int dir[][2] = {0,0,1,0,0,1,1,1};
    ll f[40];
    int main()
    {
        string s;
        cin >> s;
        ll n = s.size();
        ll x = dir[s[0] - '0'][0];
        ll y = dir[s[0] - '0'][1];
        x++,y++;
    
        for(int i = 1; i < n; i++)
        {
            x = 2 * x - 1, y = 2 * y - 1;
            if(s[i] == '1')x++;
            else if(s[i] == '2')y++;
            else if(s[i] == '3')x++,y++;
        }
        x--,y--;
        cout<<n<<" "<<x<<" "<<y<<endl;
        return 0;
    }
    View Code

    J .Jumbled Communication

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    int ans[1000];
    
    int main()
    {
        for(int i = 0; i <= 255; i++)ans[((i<<1)&255) ^ i] = i;
        int n;
        scanf("%d", &n);
        for(int i = 0; i < n; i++)
        {
            int x;
            scanf("%d", &x);
            printf("%d", ans[x]);
            if(i == n - 1)puts("");
            else putchar(' ');
        }
        return 0;
    }
    View Code

    K .Kitchen Combinatorics

    题意: 从前菜,主菜,点心中各选一道菜,每道菜由一些原料组成,每种原料有一些不同的品种,问总共有多少种方法组成这三道菜。如果多道菜使用了相同的原料,则这些菜中的这种原料将是相同品种的,另外有一些不可以组合在一起的菜。
    思路: 枚举所有可能组合,统计该组合使用不同原料的数目,将原料品种数相乘即为该组合方案数。相乘前先要用除法判断是否超过1e18

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    int r,s,m,d,n,k[100],b[1010],a[100][25];
    bool f[100][100],fl[1010];long long ans;
    int main(){
        scanf("%d%d%d%d%d",&r,&s,&m,&d,&n);
        for(int i=1;i<=r;i++)scanf("%d",b+i);
        for(int i=1;i<=s+m+d;i++){
            scanf("%d",k+i);
            for(int j=1;j<=k[i];j++)scanf("%d",a[i]+j);
        }
        for(int i=1;i<=n;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            f[x][y]=f[y][x]=1;
        }
        for(int i=1;i<=s;i++)
            for(int j=1;j<=m;j++)
                if(!f[i][s+j])
                    for(int l=1;l<=d;l++)
                        if(!f[i][l+s+m]&&!f[s+j][l+s+m]){
                            memset(fl,0,sizeof(fl));
                            for(int p=1;p<=k[i];p++)fl[a[i][p]]=1;
                            for(int p=1;p<=k[j+s];p++)fl[a[j+s][p]]=1;
                            for(int p=1;p<=k[l+s+m];p++)fl[a[l+s+m][p]]=1;
                            long long now=1;bool flag=0;
                            for(int p=1;p<=r;p++)
                                if(fl[p]){
                                    if(now>1e18/b[p])return 0*puts("too many");
                                    now*=b[p];
                                }
                            if(ans+now>1e18)return 0*puts("too many");
                            ans+=now;
                        }
        printf("%lld",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    ASP.NET 表单验证 Part.1(理解表单验证)
    Silverlight 简介 Part.3(设计 Siverlight 页面)
    ASP.NET 成员资格 Part.3(LoginStatus、LoginView、PasswordRecovery)
    ASP.NET 网站部署 Part.1(安装IIS、复制文件部署网站)
    ASP.NET Dynamic Data Part.1(创建动态数据应用程序)
    ASP.NET 安全模型 Part.2(SSL)
    ASP.NET MVC Part.2(扩展基本的 MVC 应用程序)
    ASP.NET 网站部署 Part.2(使用 Web 部署)
    开发高级 Web 部件
    创建 Web 部件(WebPart 类、简单的 Web 部件)
  • 原文地址:https://www.cnblogs.com/hua-dong/p/10525566.html
Copyright © 2011-2022 走看看