TopCoder SRM 660 Div1 250

然而我只得了95,太弱..

给一个 n 行 m 列的矩阵,矩阵元素为0-9,表示权值。现在给不超过10个集合{dx,dy},表示如果我选择了(i,j),则我就选择了集合里每个(i+dx , j+dy)点。现在要求你选择两个不同的点作为中心点(当然,它们拓展出来的点可能会重合),使得被选择的点(重复只能算一次)权值之和最大。。觉得不理解的,看tc的描述吧。

N,M 在100内,且都>=2,其他数据都在合法范围内。

这种题就乱搞。题目里数据范围小的变量往往是突破点,先说我的想法吧,一共有10000个点,对于每个(i,j),它拓展出来的点称为一个状态。那么与该状态有交集的状态最多有90个,我们不妨预处理出10000个状态,这个复杂度是O(N*M*10)的,这些状态存在一个集合里,然后暴力看每一个状态,把与它有交集的状态从集合中取出来放在另一个容器里,这个复杂度是O(N*M*90*log)的,这样,原容器里的状态都是与该状态没有交集的状态,我只需要取一个总和最大的出来就好(不需要一个一个判断,大大降低复杂度),对于新容器的状态,是有交集的,但由于不超过90个,直接暴力判,每次判是O(10)的复杂度,总共是O(N*M*90*10)。tc单case 而 跑的飞快,妥妥没问题。。比赛时候,第三步,我傻逼写成了O(N*M*90*10*log)的复杂度都1.998秒过了。。

然而我的方法不优越,说下林队长的。。你想,每个状态与它有交集的不超过90个,我把状态预处理出来,按权值和从大到小排个序,是不是取前91个,就一定能找到一个与它没有交集的且权值和最大的?那是不是排个序后,只需要枚举前91个内部就行了?92开始就不用管了。。复杂度是O(91*91*10),当然,预处理是O(N*M*10)+O(N*M*log),快得飞起。

林队长的方法

//Hello. I‘m Peter.
//#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<iostream>
#include<sstream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<cctype>
#include<ctime>
#include<stack>
#include<queue>
#include<deque>
#include<vector>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
#define peter cout<<"i am peter"<<endl
#define INT (0x3f3f3f3f)*2
#define LL (0x3f3f3f3f3f3f3f3f)*2
#define N 120
int n,m,lenset;
struct Data{
    int r,c;
    int sumval;
}data[N*N];
int numdata;
inline bool comp(const Data a,const Data b){
    return a.sumval>b.sumval;
}
int vis[N][N],nowkase;
inline bool legal(int x,int y){
    return x>=0&&x<n&&y>=0&&y<m;
}
class Coversta{
public:
    int cal(vector<string>&a,vector<int>&x,vector<int>&y,int x1,int y1,int x2,int y2){
        nowkase++;
        int sumval=0;
        for(int i=0;i<lenset;i++){
            int zx=x1+x[i];
            int zy=y1+y[i];
            if(!legal(zx,zy)) continue;
            if(vis[zx][zy]!=nowkase){
                vis[zx][zy]=nowkase;
                sumval+=a[zx][zy]-‘0‘;
            }
        }
        for(int i=0;i<lenset;i++){
            int zx=x2+x[i];
            int zy=y2+y[i];
            if(!legal(zx,zy)) continue;
            if(vis[zx][zy]!=nowkase){
                vis[zx][zy]=nowkase;
                sumval+=a[zx][zy]-‘0‘;
            }
        }
        return sumval;
    }
    int place(vector <string> a, vector <int> x, vector <int> y){
        memset(vis,-1,sizeof(vis));
        nowkase=0;
        lenset=(int)x.size();
        n=(int)a.size();
        m=(int)a[0].length();
        numdata=0;
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                int sumval=0;
                for(int k=0;k<lenset;k++){
                    int zx=i+x[k];
                    int zy=j+y[k];
                    if(!legal(zx,zy)) continue;
                    int val=a[zx][zy]-‘0‘;
                    sumval+=val;
                }
                int t=++numdata;
                data[t].r=i,data[t].c=j,data[t].sumval=sumval;
            }
        }
        int ans=-1;
        sort(data+1,data+1+numdata,comp);
        numdata=min(numdata,91);
        for(int i=1;i<=numdata;i++){
            for(int j=1;j<=numdata;j++){
                if(i==j) continue;
                ans=max(ans,cal(a,x,y,data[i].r,data[i].c,data[j].r,data[j].c));
            }
        }
        return ans;
    }
};

我的傻逼方法

//Hello. I‘m Peter.
//#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<iostream>
#include<sstream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<cctype>
#include<ctime>
#include<stack>
#include<queue>
#include<deque>
#include<vector>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
#define peter cout<<"i am peter"<<endl
#define INT (0x3f3f3f3f)*2
#define LL (0x3f3f3f3f3f3f3f3f)*2
#define N 120
int n,m,lenset;
vector<string>at;
struct Data{
    vector<pair<int,int> >v;
    int sumval;
}data[N][N];
struct Data2{
    int x,y,sumval;
    friend bool operator<(const Data2 A,const Data2 B){
        if(A.sumval!=B.sumval) return A.sumval>B.sumval;
        else if(A.x!=B.x) return A.x<B.x;
        else return A.y<B.y;
    }
}data2;
set<Data2>se;
int vis[N][N],nowkase;
inline bool legal(int x,int y){
    return x>=0&&x<n&&y>=0&&y<m;
}
class Coversta{
public:
    int cal(int x1,int y1,int x2,int y2){
        nowkase++;
        int len,sumval=0;
        len=(int)data[x1][y1].v.size();
        for(int i=0;i<len;i++){
            int x=data[x1][y1].v[i].first;
            int y=data[x1][y1].v[i].second;
            if(vis[x][y]!=nowkase){
                vis[x][y]=nowkase;
                sumval+=at[x][y]-‘0‘;
            }
        }
        len=(int)data[x2][y2].v.size();
        for(int i=0;i<len;i++){
            int x=data[x2][y2].v[i].first;
            int y=data[x2][y2].v[i].second;
            if(vis[x][y]!=nowkase){
                vis[x][y]=nowkase;
                sumval+=at[x][y]-‘0‘;
            }
        }
        return sumval;
    }
    int place(vector <string> a, vector <int> x, vector <int> y){
        memset(vis,-1,sizeof(vis));
        nowkase=0;
        at=a;
        lenset=(int)x.size();
        n=(int)a.size();
        m=(int)a[0].length();
        se.clear();
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                data[i][j].v.clear();
                int sumval=0;
                for(int k=0;k<lenset;k++){
                    int zx=i+x[k];
                    int zy=j+y[k];
                    if(!legal(zx,zy)) continue;
                    pair<int,int>p=make_pair(zx,zy);
                    int val=a[zx][zy]-‘0‘;
                    sumval+=val;
                    data[i][j].v.push_back(p);
                }
                data[i][j].sumval=sumval;
                data2.x=i,data2.y=j,data2.sumval=sumval;
                se.insert(data2);
            }
        }
        int ans=-1;
        queue<Data2>q;
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                while(!q.empty()) q.pop();
                for(int k1=0;k1<lenset;k1++){
                    int zx1=i+x[k1];
                    int zy1=j+y[k1];
                    if(!legal(zx1,zy1)) continue;
                    for(int k2=0;k2<lenset;k2++){
                        if(k1==k2) continue;
                        int zx2=zx1-x[k2];
                        int zy2=zy1-y[k2];
                        if(!legal(zx2,zy2)) continue;
                        data2.x=zx2,data2.y=zy2,data2.sumval=data[zx2][zy2].sumval;
                        if(se.find(data2)!=se.end()){
                            q.push(data2);
                            se.erase(data2);
                        }
                    }
                }
                data2.x=i,data2.y=j,data2.sumval=data[i][j].sumval;
                if(se.find(data2)!=se.end()){
                    q.push(data2);
                    se.erase(data2);
                }
                int anst=-1;
                if(!se.empty()){
                    anst=data[i][j].sumval;
                    anst+=((*se.begin()).sumval);
                    ans=max(ans,anst);
                }
                while(!q.empty()){
                    if(i!=q.front().x||j!=q.front().y){
                        anst=cal(i,j,q.front().x,q.front().y);
                        ans=max(ans,anst);
                    }
                    se.insert(q.front());
                    q.pop();
                }
            }
        }
        return ans;
    }
};
时间: 2025-01-19 10:27:05

TopCoder SRM 660 Div1 250的相关文章

Topcoder SRM 643 Div1 250&lt;peter_pan&gt;

Topcoder SRM 643 Div1 250 Problem 给一个整数N,再给一个vector<long long>v; N可以表示成若干个素数的乘积,N=p0*p1*p2*......*pn,我们假设p0,p1,...,pn是单调不降的,那么v里存储的是下标为偶数 的N的质因数p0,p2,p4,...,p(2k).现在要求写一个程序,返回一个vector<long long>ans; ans里存储的是p0,p1,p2,...,pn. Limits Time Limit(m

Topcoder SRM 648 Div1 250

Problem 给一个长度为N的"AB"字符串S,S只含有两种字符'A' 或 'B',设pair(i,j)(0=<i<j<N)表示一对 i,j 使得S[i]='A',S[j]='B'.现给定一个K,求字符串S,使得pair(i,j)的个数恰好为K.若不存在,则返回空串. Limits Time Limit(ms): 2000 Memory Limit(MB): 256 N: [2, 50] K: [0 , N*(N-1)/2 ] Solution 若K>(N/2

Topcoder SRM 345 Div1 250

题意:起初在(0,0),要到(x,y)去,每次只能横向或纵向移动.横向移动时,若所在直线y为偶数,那么只能往x轴正方向移动,若为奇数,只能往x轴反方向移动:纵向移动时,若所在直线x为偶数,那么只能往y轴正方向移动,若为奇数,只能往y轴反方向移动.问从起点到终点的最短距离是多少? x,y 范围是[-1e6, 1e6] 解法:一开始想到bfs(想到很自然),将(0, 0), (x, y), (x, 0), (0, y)这4个点分别周围9个点(包括自己)作为可达点.bfs处理出(0, 0)到(x, y

Topcoder SRM 653 Div1 250

Problem N个人坐成一排,属于同一个公司的人都坐在一起(挨在一起),但不知道谁属于哪个公司.现在问其中的某些人 他属于哪个公司,他的回答是Ai,Ai=0表示此人未被询问,否则表示他的回答.题目保证一定存在一种分组方案使得属于同一公司的人都坐在一起.现问方案是否唯一? Limits TimeLimit(ms):2000 MemoryLimit(MB):256 N,Ai∈[1,100] Solution 设dp[i]表示从i位置开始往后分组的情况,dp[i]=0表示无法分组,dp[i]=1表示

Topcoder SRM 488 Div1 250(概率dp)

题意:有n个有聊人和m个无聊人,每次等概率任选两个人,让他们都变成无聊人,求所有人都变成无聊人的期望次数.(1≤n,m≤47). 解法:设f(i)表示存在 i 个有聊人,将所有人都变成无聊人的期望次数.显然f(0) = 0,即不需要改变.方程:f(i)=f(i?2)×C2iC2n+m+f(i?1)×i×(n+m?i)C2n+m+f(i)×C2n+m?iC2n+m+1. 答案即为f(m) 代码 #include<cstdio> #include<algorithm> #include

Topcoder SRM 320 Div1 250

题意:给两个大整数,判断哪个更大.大整数以"AB"形式给出,"A"是一个不含前导0的整数(大于0,不超过1e9),"B"是若干个(可能为空)阶乘符号("!").比如:3!!=6!=720 解法:设两个大整数形式A部分分别为a,b:B部分分别有n1,n2个符号.假设n1 > n2,那么我们只需判断aA 和 b的大小即可,其中A为(n1 - n2)个阶乘符号.n1 = n2 或者 n1 < n2时候类似.但要注意有坑,

Topcoder SRM 564 Div1 250

题意:给一个n*m的棋盘,自己选择一个位置(x,y),放置一个马,马可以走到(x-1,y-1),(x-1,y-2),(x-1,y+1),(x-1,y+2),(x+1,y-1),(x+1,y-2),(x+1,y+1),(x+1,y+2) 八个位置,前提是不能走出棋盘.马可以永不停息地走.问马能走到的不同位置数最多是多少? 解法:如果n>m,swap(n,m):如果n=1,ans=1,如果n=2,ans=(m+1)>>1:如果n=3且m=3,ans=8:其他情况ans=n*m: 具体为啥,还

Topcoder SRM 547 Div1 250

Problem On a horizontal line, there are two vertical pillars. The distance between their bottoms is w. The height of the first pillar is an integer, chosen uniformly at random in the range 1 through x, inclusive. The height of the second pillar is an

Topcoder SRM 392 Div1 250

题意:给两个字符串A,B,A和B都含有小写英文字母,同时都额外含有且仅含有一个字符 ?,现希望将A,B中的字符 ? 分别替换成其它字符串(可以不同,可以相同,可以为空),使得A=B,且要求最终的A, B串(A=B)最短.或者输出不可能. 解法:让A串作为?号更靠前的串,如果A的?号之前的字符存在一个与B对应位置不同,则不可能,如果B的?号之后的字符存在一个与A对应位置不同,则不可能.否则一定有解,暴力找到最优解即可.这题可以用hash或extend-kmp的方法,达到复杂度O(N)级别,但实现有