思路:经过昨天第1题的教育后,今天第1题都虚的一档一档写了,结果在暴力的时间上花的太多了,导致想成纯hash(其实题没审清楚),正解十分从简,因为只有4种字符,k也很小,4进制枚举就行了(T_T)。
思路:神tm数学题,推导公式。
暴力15分,不解释;
当 a0 于 a1 同号时,可推出从 s=4 开始数列严格单调(题解时这么说的…),所以就暴力求出前几项就行了…
之后的一些小分的数据类同,数列一定会在s=x时严格单调,那么就要去找到这个位置,即单峰。
由于这是一道纯数学题,蒟蒻我不想多说什么了。(题解还说此题已经弱化了,原题是 Ax=k1∗Ay+k2∗Ai,x=i+2,y=i+1 )。
#include
#include
#include
#include
#include
#include
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
void 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 300005
int 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]]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]]
// }
// 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])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]if(iif(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;
}
思路:暴力bfs或dfs随意前枝应该就有50分(数据略弱),考试时也有想到要预处理每次到的状态后的答案——记忆化(75分)->dp。
记忆化这里不多说了,按照dfs的参数x(到的点),y(还剩下的钱),z(还剩下的路程)来定义就行了。
正解dp也显然要预处理,
首先考虑的还是状态,从状态定义入手,处理出 i 到 j 经过不超过 c 条路径的最大路程。
这里还需要倍增,因为从 i 到 j 的汽油量都是减少 1 的
也就是从 i 到 j 经过不超过 2k 条路径的最大路程。
然而这样还不够,最后还要二分答案or查找来优化一个小 log 卡过…
#include
#include
#include
#include
#include
#include
#include
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 17
int n,m,C,T;
struct Node{
int p,c;
}A[N];
struct edge{
int to,cost;
};
vector E[M];
struct Ans{
int s,q,d;
}Q[S];
//struct p50{
// struct node{
// int x,y,z;
// };
// queueG;
//
// 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[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].p){
// if (dis[x][y-A[x].p][A[x].c]
// 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
// 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<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 (i0 ;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题迷之爆零(切分太乱了,错的也切进去了,又因为是多测试数据,结果应该是一个测试点挂了)。
这说明我的策略还是不够到位,时间分配还不是很合理,审题的能力还不行。