2017.11.06离线赛总结

来源:互联网 发布:高干子弟知乎 编辑:程序博客网 时间:2024/06/07 12:23

dna ——3811

思路:经过昨天第1题的教育后,今天第1题都虚的一档一档写了,结果在暴力的时间上花的太多了,导致想成纯hash(其实题没审清楚),正解十分从简,因为只有4种字符,k也很小,4进制枚举就行了(T_T)。

seq ——3812

思路:神tm数学题,推导公式。
暴力15分,不解释;
a0a1同号时,可推出从s=4开始数列严格单调(题解时这么说的…),所以就暴力求出前几项就行了…
之后的一些小分的数据类同,数列一定会在s=x时严格单调,那么就要去找到这个位置,即单峰。
由于这是一道纯数学题,蒟蒻我不想多说什么了。(题解还说此题已经弱化了,原题是Ax=k1Ay+k2Ai,x=i+2,y=i+1)。

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<vector>using namespace std;#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 db double#define INF 0x3f3f3f3f#define inf 0x7fffffff#define Sz(a) sizeof(a)#define mcl(a,b) memset(a,b,Sz(a))#define mcp(a,b) memcpy(a,b,Sz(b))#define pb push_backvoid Rd(int &x){    x=0;char c;int f=1;    while(c=getchar(),c<48)if(c=='-')f=-1;    do x=(x<<1)+(x<<3)+(c^48);    while(c=getchar(),c>47);    x*=f;} #define M 100005#define N 300005int n,m;int s[M];LL f[N];int a0,a1,k;struct p15{    void solve(){        f[0]=a0,f[1]=a1;        REP(i,2,s[m])f[i]=1LL*k*f[i-1]+f[i-2];        LL Mx=-INF,Mn=INF;        int Mx_id=s[1],Mn_id=s[1];        REP(i,1,m){            if(f[s[i]]>Mx)Mx_id=s[i],Mx=f[s[i]];            if(f[s[i]]<Mn)Mn_id=s[i],Mn=f[s[i]];         }        printf("%d %d\n",Mx_id,Mn_id);    }}p15;//struct p20{//  void solve(){//      REP(i,2,10)f[i]=1LL*k*f[i-1]+f[i-2];//      LL Mx=-INF,Mn=INF;//      int Mx_id=s[1],Mn_id=s[1];//      REP(i,1,m){//          if(s[i]>5)break; //          if(f[s[i]]>Mx)Mx_id=s[i],Mx=f[s[i]];//          if(f[s[i]]<Mn)Mn_id=s[i],Mn=f[s[i]]; //      }//      if(f[8]<0)printf("%d %d\n",Mx_id,s[m]);//      else printf("%d %d\n",s[m],Mn_id);//  }//}p20;struct p100{    void solve(){        f[0]=a0,f[1]=a1;        int Mx_id=s[1],Mn_id=s[1];        int i;        for(i=2;i<=s[m];i++){            f[i]=1LL*k*f[i-1]+f[i-2];            if(  (f[i-1]>=0) == (f[i]>=0) ){                if(f[i]<0 && min(f[i],f[i-1])<min(f[0],f[1]) )break;                if(f[i]>0 && max(f[i],f[i-1])>max(f[0],f[1]) )break;            }         }        for(int j=2;s[j]<=i && j<=m;j++){            if(f[Mn_id]>f[s[j]])Mn_id=s[j];            if(f[Mx_id]<f[s[j]])Mx_id=s[j];        }        if(i<s[m]){            if(f[i]<0)Mn_id=s[m];            if(f[i]>0)Mx_id=s[m];         }        printf("%d %d\n",Mx_id,Mn_id);    }}p100;int main(){//  freopen("seq.in","r",stdin);//  freopen("seq.out","w",stdout);//  printf("%d\n",(Sz(f)+Sz(s))/1024/1024);    cin>>m;    REP(i,1,m)Rd(s[i]);    cin>>n;    REP(i,1,n){        Rd(a0),Rd(a1),Rd(k);        if(!a0 && !a1)printf("%d %d\n",s[1],s[1]);         else if(n<=100 && m<=100 && s[m]<=10)p15.solve();        else p100.solve();    }    return 0;}

trip ——3812

思路:暴力bfs或dfs随意前枝应该就有50分(数据略弱),考试时也有想到要预处理每次到的状态后的答案——记忆化(75分)->dp。
记忆化这里不多说了,按照dfs的参数x(到的点),y(还剩下的钱),z(还剩下的路程)来定义就行了。
正解dp也显然要预处理,
首先考虑的还是状态,从状态定义入手,处理出ij 经过不超过c条路径的最大路程。
这里还需要倍增,因为从ij的汽油量都是减少1
也就是从ij经过不超过2k 条路径的最大路程。
然而这样还不够,最后还要二分答案or查找来优化一个小log卡过…

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<vector>#include<queue> using namespace std;#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 db double     #define INF 0x3f3f3f3f#define inf 0x7fffffff#define Sz(a) sizeof(a)#define mcl(a,b) memset(a,b,Sz(a))#define mcp(a,b) memcpy(a,b,Sz(b))#define pb push_back#define N 105#define M 1005#define S 100005#define TM 17int n,m,C,T;struct Node{    int p,c;}A[N];struct edge{    int to,cost;};vector<edge>E[M];struct Ans{    int s,q,d;}Q[S];//struct p50{//  struct node{//      int x,y,z;//  };//  queue<node>G;//   //  int dis[N][M][N];//  bool mark[N][M][N];//   //    void solve(){//        REP(i,1,T){//            int ans=-1;//            mcl(dis,-1); //            dis[Q[i].s][Q[i].q][0]=0;//            G.push((node){Q[i].s,Q[i].q,0});//             //            while(!G.empty()){//                int x=G.front().x,y=G.front().y,z=G.front().z;//                G.pop();//                mark[x][y][z]=0;//                if(dis[x][y][z]>=Q[i].d){ans=max(ans,y);continue;}//                if(y<=ans)continue;//                if(z){//                    REP(j,0,E[x].size()-1){//                        int to=E[x][j].to,cost=E[x][j].cost;//                        if (dis[to][y][z-1]<dis[x][y][z]+cost){//                            dis[to][y][z-1]=dis[x][y][z]+cost;//                            if (!mark[to][y][z-1]){//                                mark[to][y][z-1]=1;//                                G.push((node){to,y,z-1});//                            }//                        }//                    }//                }//                if (z<A[x].c && y>=A[x].p){//                    if (dis[x][y-A[x].p][A[x].c]<dis[x][y][z]){//                        dis[x][y-A[x].p][A[x].c]=dis[x][y][z];//                        if (!mark[x][y-A[x].p][A[x].c]){//                            mark[x][y-A[x].p][A[x].c]=1;//                            G.push((node){x,y-A[x].p,A[x].c});//                        }//                    }//                }   //            }//            printf("%d\n",ans);//        }//    }//}p50;  //struct p75{//    LL dp[N][570][M];//    LL dfs(int x,LL money,int res){//        LL &t=dp[x][money][res];//        if(t!=-1)return t;//        t=0;//        REP(i,0,E[x].size()-1){//            edge y=E[x][i];//            if(money>=A[x].p&&res<A[x].c)t=max(t,dfs(y.to,money-A[x].p,A[x].c-1)+y.cost);//            if(res)t=max(t,dfs(y.to,money,res-1)+y.cost);//        }//        return t;//    }//    void solve(){//        memset(dp,-1,sizeof(dp));//        REP(j,1,T){//            int ans=-1;//            REP(i,0,Q[j].q){//                LL res=dfs(Q[j].s,i,0);//                if(res>=Q[j].d){//                    ans=Q[j].q-i;//                    break;//                }//            }//            printf("%d\n",ans);//        }//    }//}p75;int dp[N][N*N],f[N][N][TM],w[N][N],tmp[N];struct p100{    void Init(){        mcl(w,192);        REP(i,1,n)w[i][i]=0;        REP(l,1,TM-1)            REP(i,1,n)                REP(j,1,n){                    f[i][j][l]=f[i][j][l-1];                    REP(k,1,n)f[i][j][l]=max(f[i][j][l],f[i][k][l-1]+f[k][j][l-1]);                }        REP(l,0,TM-1){            REP(i,1,n){                if(!((1<<l)&A[i].c))continue;                mcl(tmp,192);                REP(j,1,n)REP(k,1,n)tmp[j]=max(tmp[j],w[i][k]+f[k][j][l]);                REP(j,1,n)w[i][j]=max(w[i][j],tmp[j]);            }        }        mcl(dp,192);        REP(i,0,n*n)            REP(j,1,n){                if (i<A[j].p){dp[j][i]=0;continue;}                REP(k,1,n)dp[j][i]=max(dp[j][i],w[j][k]+dp[k][i-A[j].p]);            }    }       void solve(){        mcl(dp,-1);        Init();        REP(i,1,T){            int L=0,R=Q[i].q,used=Q[i].q+1;            while(L<=R){                int mid=(L+R)>>1;                if(dp[Q[i].s][mid]>=Q[i].d)used=mid,R=mid-1;                else L=mid+1;            }            printf("%d\n",Q[i].q-used);        }    }}p100;int main(){//      freopen("trip.in","r",stdin);//      freopen("trip.out","w",stdout);    cin>>n>>m>>C>>T;    REP(i,1,n){        scanf("%d%d",&A[i].p,&A[i].c);        A[i].c=min(A[i].c,C);    }    mcl(f,192);    REP(i,1,m){        int x,y,z;        scanf("%d%d%d",&x,&y,&z);        E[x].pb((edge){y,z});        f[x][y][0]=max(f[x][y][0],z);    }    REP(i,1,T)scanf("%d%d%d",&Q[i].s,&Q[i].q,&Q[i].d);//      p50.solve();//      p75.solve();    p100.solve();    return 0;}

小结:今天考得不好,讲道理应该有165,结果比暴力的分(150)还少(130分)…可能还是第1题的策略没搞好,而且第2题迷之爆零(切分太乱了,错的也切进去了,又因为是多测试数据,结果应该是一个测试点挂了)。
这说明我的策略还是不够到位,时间分配还不是很合理,审题的能力还不行。

原创粉丝点击