zoukankan      html  css  js  c++  java
  • 中大ACM个人赛 ABC题题解

    摸完签到题就跑了

    A - Maximum Subrectangle

    题意:有个C矩阵,C[i][j] = a[i]b[j], 问你在(displaystylesum_{i=x1}^{x2}) (displaystylesum_{j=y1}^{y2}) (C_{i,j}) <= x的条件下能选出来最大子矩阵。

    思路:不妨设这个子矩阵的左上角为(i,j), 右下角为(i+len1-1,j+len2-1),其中len1,len2分别代表长和宽(或宽和长)。
    这个时候可以把元素和写成(a[i] + a[i+1] ... + a[i+len1-1])(b[j] + b[j+1] + ... b[j+len2-1]),这可以看成在a数组中挑出一个长度为len1的子串,在b数组中挑出一个长度为len2的子串,两者的子串和相乘。那么我们要想选出总共那么多个数的时候,各自的和尽量的小(贪心),这样才能使得相乘起来更小。比如这里的len1长度的a子串和len2长度的b子串,我要挑肯定挑各自那么长的子串中最小的。
    所以问题就变成了我要在各自的数组里面先计算好长度为len时的最优解,然后遍历各自取出的长度即可。时间复杂度O((n^2))。

    view code
    #include<iostream>
    #include<string>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<map>
    #include <queue>
    #include<sstream>
    #include <stack>
    #include <set>
    #include <bitset>
    #include<vector>
    #define FAST ios::sync_with_stdio(false)
    #define abs(a) ((a)>=0?(a):-(a))
    #define sz(x) ((int)(x).size())
    #define all(x) (x).begin(),(x).end()
    #define mem(a,b) memset(a,b,sizeof(a))
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    #define rep(i,a,n) for(int i=a;i<=n;++i)
    #define per(i,n,a) for(int i=n;i>=a;--i)
    #define pb push_back
    #define mp make_pair
    #define fi first
    #define se second
    using namespace std;
    typedef long long ll;
    typedef pair<ll,ll> PII;
    const int maxn = 2e3+200;
    const ll inf=0x3f3f3f3f3f3f3f3f;
    const double eps = 1e-7;
    const double pi=acos(-1.0);
    const int mod = 1e9+7;
    inline int lowbit(int x){return x&(-x);}
    ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
    void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y){if(!b){d=a,x=1,y=0;}else{ex_gcd(b,a%b,d,y,x);y-=x*(a/b);}}//x=(x%(b/d)+(b/d))%(b/d);
    inline ll qpow(ll a,ll b,ll MOD=mod){ll res=1;a%=MOD;while(b>0){if(b&1)res=res*a%MOD;a=a*a%MOD;b>>=1;}return res;}
    inline ll inv(ll x,ll p){return qpow(x,p-2,p);}
    inline ll Jos(ll n,ll k,ll s=1){ll res=0;rep(i,1,n+1) res=(res+k)%i;return (res+s)%n;}
    inline ll read(){ ll f = 1; ll x = 0;char ch = getchar();while(ch>'9'||ch<'0') {if(ch=='-') f=-1; ch = getchar();}while(ch>='0'&&ch<='9') x = (x<<3) + (x<<1) + ch - '0',  ch = getchar();return x*f; }
    int dir[4][2] = { {1,0}, {-1,0},{0,1},{0,-1} };
    
    ll n, m;
    ll a[maxn], b[maxn];
    ll pre1[maxn], pre2[maxn];  //pre[i]代表子串长度为i时的最小和
    ll sum1[maxn],sum2[maxn];
    
    int main()
    {
        n = read(), m = read();
        rep(i,1,n) a[i] = read(), sum1[i] = a[i] + sum1[i-1];
        rep(i,1,m) b[i] = read(), sum2[i] = b[i] + sum2[i-1];
        ll x = read();
        rep(len,1,n)
        {
            ll mi = inf;
            rep(j,len,n) mi = min(mi, sum1[j] - sum1[j-len]);
            pre1[len] = mi;
        }
         rep(len,1,m)
        {
            ll mi = inf;
            rep(j,len,m) mi = min(mi, sum2[j] - sum2[j-len]);
            pre2[len] = mi;
        }
        ll ans = 0;
        rep(i,1,n) rep(j,1,m)
        {
            if(pre1[i]*pre2[j] <= x) ans = max(ans, i*j);
        }
        cout<<ans<<'
    ';
        return 0;
    }
    
    
    

    B - Barcelonian Distance

    题意:给你两个点,每步只能按照曼哈顿路径走,但是也给了你一条直线,如果在直线上就能沿着直线滑行。问你从A到B的最短路。

    思路:其实不用想那么多,建边跑最短路floyd就行。一共有六个点:
    1.A点。
    2.A横着到直线相交的那个点。
    3.A竖着到直线相交的点。
    4.B点。
    5.B横着交直线的点。
    6.B竖着交直线的点。
    这几个点先求出来然后建边,跑个floyd直接输出就好。
    另外一个方法就是枚举这几种路径,就是麻烦了一点,效果一样:
    1.A直接曼哈顿距离到B。
    2.A沿着直线上,有两种方法,然后从直线到B,也有两种方法。
    以上五种方法全写出来取最小就行。不过还是直接floyd香。

    view code
    #include<iostream>
    #include<string>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<map>
    #include <queue>
    #include<sstream>
    #include <stack>
    #include <set>
    #include <bitset>
    #include<vector>
    #define FAST ios::sync_with_stdio(false)
    #define abs(a) ((a)>=0?(a):-(a))
    #define sz(x) ((int)(x).size())
    #define all(x) (x).begin(),(x).end()
    #define mem(a,b) memset(a,b,sizeof(a))
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    #define rep(i,a,n) for(int i=a;i<=n;++i)
    #define per(i,n,a) for(int i=n;i>=a;--i)
    #define pb push_back
    #define mp make_pair
    #define fi first
    #define se second
    using namespace std;
    typedef long long ll;
    typedef pair<ll,ll> PII;
    const int maxn = 1e5+200;
    const int inf=0x3f3f3f3f;
    const double eps = 1e-7;
    const double pi=acos(-1.0);
    const int mod = 1e9+7;
    inline int lowbit(int x){return x&(-x);}
    ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
    void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y){if(!b){d=a,x=1,y=0;}else{ex_gcd(b,a%b,d,y,x);y-=x*(a/b);}}//x=(x%(b/d)+(b/d))%(b/d);
    inline ll qpow(ll a,ll b,ll MOD=mod){ll res=1;a%=MOD;while(b>0){if(b&1)res=res*a%MOD;a=a*a%MOD;b>>=1;}return res;}
    inline ll inv(ll x,ll p){return qpow(x,p-2,p);}
    inline ll Jos(ll n,ll k,ll s=1){ll res=0;rep(i,1,n+1) res=(res+k)%i;return (res+s)%n;}
    inline ll read(){ ll f = 1; ll x = 0;char ch = getchar();while(ch>'9'||ch<'0') {if(ch=='-') f=-1; ch = getchar();}while(ch>='0'&&ch<='9') x = (x<<3) + (x<<1) + ch - '0',  ch = getchar();return x*f; }
    int dir[4][2] = { {1,0}, {-1,0},{0,1},{0,-1} };
    
    double dp[20][20];
    double a, b, c;
    double x1, y1 , x2, y2;
    typedef struct Pos
    {
        double x;
        double y;
    }P;
    P point[10];
    
    int main()
    {
        cin>>a>>b>>c;
        cin>>x1>>y1>>x2>>y2;
        rep(i,1,10) rep(j,1,10) if(i!=j) dp[i][j] = 1e18;
        dp[1][6] = dp[6][1] = fabs(x1 - x2) + fabs(y1 - y2);
        if(a!=0&&b!=0)
        {
            point[1].x = x1;
            point[1].y = y1;
    
            point[2].x = x1;
            point[2].y = -(a*x1 + c)/b;
    
            point[3].x = -(b*y1+c)/a;
            point[3].y = y1;
    
            point[4].x = x2;
            point[4].y = -(a*x2 + c)/b;
    
            point[5].x = -(b*y2+c)/a;
            point[5].y = y2;
    
            point[6].x = x2;
            point[6].y = y2;
    
            rep(i,2,5) dp[1][i] = dp[i][1] = fabs(x1 - point[i].x) + fabs(y1 - point[i].y),dp[6][i] = dp[i][6] = fabs(x2 - point[i].x) + fabs(y2 - point[i].y);
            rep(i,2,5) rep(j,i+1,5) dp[i][j] = dp[j][i] = sqrt((point[i].x - point[j].x)*(point[i].x - point[j].x) +(point[i].y - point[j].y)*(point[i].y - point[j].y)  );
        }
        rep(k,1,6) rep(i,1,6) rep(j,1,6) dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j]);
        printf("%f
    ", dp[1][6]);
        return 0;
    }
    
    

    C - The Unbearable Lightness of Weights

    题意:找到最大的k,使得有k个相同的数组成的和m,是被唯一得到的。

    思路:其实根本不太懂题目问什么。看别人博客的题意来写的。
    要满足上述限制还要最优,我们的策略就是尽量挑大的k,然后我们要check一下挑k个a[i]后组成的sum是否唯一得到。
    所以事先要做一遍背包,以dp[i][j]表示用j个物品凑到i重量的方案数。转移时外层用1->n个砝码去铺,内层做一个背包。转移方程为:
    dp[j][k] += dp[j-a[i]][k]。
    这个预处理完后就是上面说的check,我挑k个a[i],看看dp[k*a[i]][k]是否等于(C_{Map[a[i]]}^{k}),其中Map[a[i]]为a[i]的个数。简单排列组合问题。
    最后有点疑惑的是不知道为啥种类为2的时候也能得到所有,可能还是不太理解题意吧。

    view code
    #include<iostream>
    #include<string>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<map>
    #include <queue>
    #include<sstream>
    #include <stack>
    #include <set>
    #include <bitset>
    #include<vector>
    #define FAST ios::sync_with_stdio(false)
    #define abs(a) ((a)>=0?(a):-(a))
    #define sz(x) ((int)(x).size())
    #define all(x) (x).begin(),(x).end()
    #define mem(a,b) memset(a,b,sizeof(a))
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    #define rep(i,a,n) for(int i=a;i<=n;++i)
    #define per(i,n,a) for(int i=n;i>=a;--i)
    #define pb push_back
    #define mp make_pair
    #define fi first
    #define se second
    using namespace std;
    typedef long long ll;
    typedef pair<ll,ll> PII;
    const int maxn = 1e5+200;
    const int inf=0x3f3f3f3f;
    const double eps = 1e-7;
    const double pi=acos(-1.0);
    const int mod = 1e9+7;
    inline int lowbit(int x){return x&(-x);}
    ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
    void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y){if(!b){d=a,x=1,y=0;}else{ex_gcd(b,a%b,d,y,x);y-=x*(a/b);}}//x=(x%(b/d)+(b/d))%(b/d);
    inline ll qpow(ll a,ll b,ll MOD=mod){ll res=1;a%=MOD;while(b>0){if(b&1)res=res*a%MOD;a=a*a%MOD;b>>=1;}return res;}
    inline ll inv(ll x,ll p){return qpow(x,p-2,p);}
    inline ll Jos(ll n,ll k,ll s=1){ll res=0;rep(i,1,n+1) res=(res+k)%i;return (res+s)%n;}
    inline ll read(){ ll f = 1; ll x = 0;char ch = getchar();while(ch>'9'||ch<'0') {if(ch=='-') f=-1; ch = getchar();}while(ch>='0'&&ch<='9') x = (x<<3) + (x<<1) + ch - '0',  ch = getchar();return x*f; }
    int dir[4][2] = { {1,0}, {-1,0},{0,1},{0,-1} };
    
    ll n;
    ll dp[10005][105];    //dp[i][j]表示用j件物品凑到i重量的方案数
    ll C[105][105];
    ll a[maxn];
    map<ll,ll> Map;
    
    void init()
    {
        rep(i,0, 102) C[i][0] = 1;
        rep(i,1,102) rep(j,1,i) C[i][j] = (C[i-1][j]+C[i-1][j-1])%mod;
    }
    
    int main()
    {
        init();
        n = read();
        ll sum = 0;
        rep(i,1,n) a[i] = read(), sum += a[i], Map[a[i]]++;
        dp[0][0] = 1;
        rep(i,1,n) per(j,sum,a[i]) rep(k,1,i) dp[j][k] = (dp[j][k] + dp[j - a[i]][k-1]) % mod;
        if(Map.size()<=2)
        {
            cout<<n<<'
    ';
            return 0;
        }
        ll ans = 0;
        for(auto it = Map.begin(); it != Map.end(); it++)
        {
            ll cur = it->fi;
            rep(i,1,it->se) if(dp[cur*i][i] == C[it->se][i]) ans = max(ans,i);
        }
        cout<<ans<<'
    ';
        return 0;
    }
    
    
  • 相关阅读:
    jdk和dubbo的SPI机制
    何谓架构
    ElasticSearch的API使用
    LFU的基本原理与实现
    如何判断单向链表有环?
    mysql执行过程以及顺序
    原来 TinyPNG 可以这样玩!
    deno + mongodb 实战踩坑记
    好消息,vue3.0 进入 beta 阶段!
    听说会做这道题的人后来都进了头条?
  • 原文地址:https://www.cnblogs.com/Bgwithcode/p/13619674.html
Copyright © 2011-2022 走看看