2017.10.6离线赛总结

第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 100005
using 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 505
using 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,内存)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值