2017.10.6离线赛总结

来源:互联网 发布:mac book air 输入法 编辑:程序博客网 时间:2024/06/07 21:10

第1题:构造序列
题意:构造一个长度为n的序列,每个元素的范围是[1,k];
对于相邻的两个元素A,B(A在前,B在后),满足A<=B 或者A%B!=0
求方案数,对1e9+7求余。(个人觉得原题意已经很精辟了)

数据范围:
80%,n<=10,k<=1000;
100%,n<=10,k<=10^5;

思路:今天一看第1题有点小懵逼,以往的第1题都是一看就ac的(自我水平还有待提高),然而确实不会难呀(小c)。
P80:dp,dp[i][j]表示第i为j的方案。O(n*k^2);(当时也是急了,mod都忘了,今天也就跪在了这里…)
P100:前缀和维护上一层的方案,仔细分析题目条件A<=B很容易no problem,A%B!=0 实际上就是去找B的倍数!(赛后一切都是屁话)
所以先加上所有的方案,再减掉它的倍数的方案。(注意过程要mod呀!)

#include<bits/stdc++.h>#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;i++)#define LL long long#define N 15#define M 100005using namespace std;const int P=1e9+7;int n,K;LL ans;LL dp[N][M];struct P80{    void solve(){        REP(i,1,n-1){            REP(j,1,K){                REP(k,1,K){                    if(k>=j || j%k!=0)dp[i+1][k]+=dp[i][j],dp[i+1][k]%=P;                }            }        }        REP(i,1,K)ans+=dp[n][i],ans%=P;        cout<<ans<<endl;    }}p80;struct P100{    int sum[M];    void solve(){        REP(i,2,K){            sum[i]=K;            for(int j=2;j*i<=K;j++)sum[i]-=dp[1][i*j];        }        REP(i,2,n){            int tmp=1;            REP(j,2,K){                dp[i][j]+=sum[j],dp[i][j]%=P;                tmp+=dp[i][j],tmp%=P;            }            REP(j,1,K){                sum[j]=tmp;                for(int k=2;k*j<=K;k++)sum[j]-=dp[i][j*k],sum[j]=(sum[j]+P)%P;//-            }        }        LL ans=1;        REP(i,2,K)ans+=dp[n][i],ans%=P;        cout<<ans<<endl;     }}p100;int main(){    scanf("%d%d",&n,&K);    REP(i,1,K)dp[1][i]=1;    if(K<=1000)p80.solve();    else p100.solve();    return 0;}

第2题:1/2背包
题意:体积m,n个物品(cost,v),与普通的背包问题类似,但此题的cost=1 or 2。(这也成就了数据的范围和思路)

数据范围:
60%,n<=2000,m<=10^4;
100%,n<=2*10^5,m<=5*10^5,v<=10^4;

思路:
P60:普通的01背包,这里不解释了;
P100:由于此题的cost=1 or 2 ,给人的感觉就是可以贪心,按性价比去排序,(你说你不造性价比是什么,那就很尴尬了)。

第3题:引水入城
题意:n*m的矩形城市,第1行的城市濒临湖泊,可以蓄水,建造蓄水厂,为相邻的城市传输水,然而两个城市传输水的条件是自然法则(水从高处流,自然要海拔差);第n行的城市靠近沙漠,为干旱区,需水源。所以问题来了,能否满足所有干旱区的城市都有水,(0为否,1为是),若满足,则输出最小要建造的蓄水厂数,否则,输出干旱区有多少城市缺水。

数据范围:
100%:n,m<=500

思路:
P60:听说暴力就60(不好意思,今天想到正解了);
P100:此题的问法,显然分2个步骤。1,判断是否满足要求,这里bfs就行了;2,不满足的话好说,可以直接累计mark[n][1~m],而满足的话,就再dfs,记录每个蓄水厂到第n行的[L,R],且这里蓄水厂所到达的区间都不会交集(据题意,也是很好证明的),那就dp求出这个最小值,(也是一开始前2题都是dp的错觉)。

#include<bits/stdc++.h>#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;i++)#define DREP(i,f,t) for(int i=(f),i##_end_=(t);i>=i##_end_;i--)#define LL long long#define INF 0x3f3f3f3f#define N 505using namespace std;int n,m,ans;int h[N][N];bool mark[N][N];struct node{    int x,y;};queue<node>Q;int dx[]={-1,0,1,0},dy[]={0,-1,0,1};void Rd(){    scanf("%d%d",&n,&m);    REP(i,1,n)REP(j,1,m)scanf("%d",&h[i][j]);}bool check(int x,int y){return !x || x>n || !y || y>m || mark[x][y];}struct P100{    void bfs(){        REP(i,1,m)mark[1][i]=1,Q.push((node){1,i});        while(!Q.empty()){            node now=Q.front();Q.pop();            REP(i,0,3){                int nx=now.x+dx[i],ny=now.y+dy[i];                if(check(nx,ny))continue;                if(h[now.x][now.y]<=h[nx][ny])continue;                mark[nx][ny]=1;                Q.push((node){nx,ny});            }        }    }    struct city{        int L,R;    }C[N];    int now_id;    int dp[N];    void dfs(node now){        mark[now.x][now.y]=1;        if(now.x==n){            C[now_id].L=min(C[now_id].L,now.y);            C[now_id].R=max(C[now_id].R,now.y);        }        REP(i,0,3){            int nx=now.x+dx[i],ny=now.y+dy[i];            if(check(nx,ny))continue;            if(h[now.x][now.y]<=h[nx][ny])continue;            if(!mark[nx][ny])dfs((node){nx,ny});        }    }    void solve(){        bfs();        REP(i,1,m)if(!mark[n][i])ans++;        if(ans>0){            printf("0\n%d\n",ans);            exit(0);        }        REP(i,1,m){            memset(mark,0,sizeof(mark));            C[i]=(city){m+1,0};            now_id=i;            dfs((node){1,i});        }        ans=INF;        memset(dp,INF,sizeof(dp));        dp[0]=0;        REP(i,1,m){            REP(j,1,m){                if(i<C[j].L || i>C[j].R)continue;                dp[i]=min(dp[i],dp[C[j].L-1]+1);            }        }        printf("1\n%d\n",dp[m]);    }}p100;int main(){    Rd();     p100.solve();    return 0;}

小结:
这次虽然考得不错,每题都做到了且分,但没有mod,还有犯如此低级的错误,也有什么可说的。下次直接在define下面打上(LL,mod,内存)。

原创粉丝点击