3.14杂题选讲
强烈谴责这次的出题人把难度搞这么高,让我这个菜鸡怎么活……
T1
非常显然的思路是01分数规划,然后就不会做了(大雾
考虑\(a\)小的可以连接到\(a\)大的任务上一起做,那么显然也可以把任务按\(a\)排序后相同的放在一起分组。
然后就可以开心快乐地DP了。
设\(dp_{i,j}\)表示前\(i\)组里有\(j\)个记入答案,所能得到的最小权值(权值就是01分数规划搞出来的东西)。
于是有转移方程:
其中\(W_{i,k}\)表示第\(i\)组里权值最小的\(k\)个的权值之和,随便处理一下就好了。
注意一个状态要合法需要满足一些条件,可以自己推一下。
#include<bits/stdc++.h>
clock_t t=clock();
namespace my_std{
using namespace std;
#define pii pair<int,int>
#define fir first
#define sec second
#define MP make_pair
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
#define drep(i,x,y) for (int i=(x);i>=(y);i--)
#define go(x) for (int i=head[x];i;i=edge[i].nxt)
#define templ template<typename T>
#define sz 100
typedef long long ll;
typedef long double db;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
templ inline T rnd(T l,T r) {return uniform_int_distribution<T>(l,r)(rng);}
templ inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
templ inline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
templ inline void read(T& t)
{
t=0;char f=0,ch=getchar();double d=0.1;
while(ch>'9'||ch<'0') f|=(ch=='-'),ch=getchar();
while(ch<='9'&&ch>='0') t=t*10+ch-48,ch=getchar();
if(ch=='.'){ch=getchar();while(ch<='9'&&ch>='0') t+=d*(ch^48),d*=0.1,ch=getchar();}
t=(f?-t:t);
}
template<typename T,typename... Args>inline void read(T& t,Args&... args){read(t); read(args...);}
char sr[1<<21],z[20];int C=-1,Z=0;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
inline void print(register int x)
{
if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
while(z[++Z]=x%10+48,x/=10);
while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
void file()
{
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
#endif
}
inline void chktime()
{
#ifndef ONLINE_JUDGE
cout<<(clock()-t)/1000.0<<'\n';
#endif
}
#ifdef mod
ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x%mod) if (y&1) ret=ret*x%mod;return ret;}
ll inv(ll x){return ksm(x,mod-2);}
#else
ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x) if (y&1) ret=ret*x;return ret;}
#endif
// inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
}
using namespace my_std;
int n;
struct hh{ll a,b;inline bool operator < (const hh &y) const {return a>y.a;}}a[sz];
vector<db>w[sz],sum[sz];
int c[sz];
db dp[sz][sz]; // Ç°i×飬ÓÐj¸öÓÐЧµÄ£¬µÃµ½µÄ×î´óȨֵ
// j*2 \geq c[i]
bool judge(db W)
{
int cnt=0;
rep(i,1,n) w[i].resize(0),sum[i].resize(0);
rep(i,1,n)
{
if (i==1||a[i].a!=a[i-1].a) ++cnt;
w[cnt].push_back(a[i].a-W*a[i].b);
}
rep(i,1,cnt)
{
sort(w[i].begin(),w[i].end());
sum[i].resize(w[i].size());
sum[i][0]=w[i][0];
c[i]=c[i-1]+w[i].size();
rep(j,1,(int)sum[i].size()-1) sum[i][j]=sum[i][j-1]+w[i][j];
}
rep(i,0,n) rep(j,0,c[cnt]) dp[i][j]=1e19;
dp[0][0]=0;
rep(i,1,cnt)
rep(j,1,c[i])
if (j*2>=c[i])
{
dp[i][j]=dp[i-1][j];
rep(k,1,min(j,c[i]-c[i-1])) if (c[i]-c[i-1]-k<=j*2-c[i-1]-2*k)
chkmin(dp[i][j],dp[i-1][j-k]+sum[i][k-1]);
}
db ret=1e19;
rep(i,1,n) chkmin(ret,dp[cnt][i]);
return ret<=0;
}
int main()
{
file();
read(n);
rep(i,1,n) read(a[i].a);
rep(i,1,n) read(a[i].b);
sort(a+1,a+n+1);
db l=0,r=1e10;
while (r-l>=1e-7)
{
db mid=(l+r)/2;
if (judge(mid)) r=mid;
else l=mid;
}
printf("%lld",(ll)ceil(l*1000));
return 0;
}
T2
第一问非常无趣,\(a_i=a_i-i\)后求一个\(a\)的最长不下降子序列就好了。
记\(dp_i\)表示以\(i\)结尾的最长不降子序列长度。
第二问考虑DP,设\(f_i\)表示\(i\)不变,前\(i\)个都已经变为不降序列的最小代价。
\(f_i\)可以由\(f_j\)转移而来,其中\(j<i\;\;\&\&\;\;dp_j=dp_i-1\)。
注意到一个性质:这段区间中的\(k\)都满足\(a_j>a_k \; \; or \;\; a_k>a_i\)。
所以可以感受一下,\(j\rightarrow i\)之间的\(a\)必然会变成这样:一段都等于\(a_j\),后一段等于\(a_i\)。如果不是这样也可以调整成这样。
然后暴力枚举分界点即可。
复杂度似乎很大,但数据随机,也就这么跑过去了。
#include<bits/stdc++.h>
clock_t t=clock();
namespace my_std{
using namespace std;
#define pii pair<int,int>
#define fir first
#define sec second
#define MP make_pair
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
#define drep(i,x,y) for (int i=(x);i>=(y);i--)
#define go(x) for (int i=head[x];i;i=edge[i].nxt)
#define templ template<typename T>
#define sz 50500
typedef long long ll;
typedef double db;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
templ inline T rnd(T l,T r) {return uniform_int_distribution<T>(l,r)(rng);}
templ inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
templ inline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
templ inline void read(T& t)
{
t=0;char f=0,ch=getchar();double d=0.1;
while(ch>'9'||ch<'0') f|=(ch=='-'),ch=getchar();
while(ch<='9'&&ch>='0') t=t*10+ch-48,ch=getchar();
if(ch=='.'){ch=getchar();while(ch<='9'&&ch>='0') t+=d*(ch^48),d*=0.1,ch=getchar();}
t=(f?-t:t);
}
template<typename T,typename... Args>inline void read(T& t,Args&... args){read(t); read(args...);}
char sr[1<<21],z[20];int C=-1,Z=0;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
inline void print(register int x)
{
if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
while(z[++Z]=x%10+48,x/=10);
while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
void file()
{
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
#endif
}
inline void chktime()
{
#ifndef ONLINE_JUDGE
cout<<(clock()-t)/1000.0<<'\n';
#endif
}
#ifdef mod
ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x%mod) if (y&1) ret=ret*x%mod;return ret;}
ll inv(ll x){return ksm(x,mod-2);}
#else
ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x) if (y&1) ret=ret*x;return ret;}
#endif
// inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
}
using namespace my_std;
int n;
int a[sz];
int dp[sz];
int mn[sz],top;
ll f[sz];
vector<int>v[sz];
int main()
{
file();
read(n);
rep(i,1,n) read(a[i]),a[i]-=i;
mn[0]=-1e9;
a[n+1]=1e9;
rep(i,1,n+1)
{
int pos=upper_bound(mn,mn+top+1,a[i])-mn-1;
dp[i]=pos+1;
if (pos==top) ++top,mn[top]=1e9;
chkmin(mn[pos+1],a[i]);
}
printf("%d\n",n-dp[n+1]+1);
rep(i,1,n+1) v[dp[i]].push_back(i);
v[0].push_back(0);
rep(i,1,n+1) f[i]=1e18;
a[0]=-1e9;f[0]=0;
rep(i,1,n+1)
{
for (int x:v[dp[i]-1]) if (a[x]<=a[i]&&x<i)
{
ll sum1=0,sum2=0;
rep(j,x+1,i-1) sum2+=abs(a[j]-a[i]);
ll cur=sum2;
rep(j,x+1,i-1) sum1+=abs(a[j]-a[x]),sum2-=abs(a[j]-a[i]),chkmin(cur,sum1+sum2);
chkmin(f[i],f[x]+cur);
}
}
cout<<f[n+1];
return 0;
}
T3
这题没做出来,我的脑子呢……
直接给邻接矩阵做矩阵乘法,相当于是DP。
由于食人鱼的周期特别短,取\(12\)为一周期,把每一个时刻的邻接矩阵处理出来,然后瞎乘一通就好了。
#include<bits/stdc++.h>
clock_t t=clock();
namespace my_std{
using namespace std;
#define pii pair<int,int>
#define fir first
#define sec second
#define MP make_pair
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
#define drep(i,x,y) for (int i=(x);i>=(y);i--)
#define go(x) for (int i=head[x];i;i=edge[i].nxt)
#define templ template<typename T>
#define sz 55
#define mod 10000
typedef long long ll;
typedef double db;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
templ inline T rnd(T l,T r) {return uniform_int_distribution<T>(l,r)(rng);}
templ inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
templ inline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
templ inline void read(T& t)
{
t=0;char f=0,ch=getchar();double d=0.1;
while(ch>'9'||ch<'0') f|=(ch=='-'),ch=getchar();
while(ch<='9'&&ch>='0') t=t*10+ch-48,ch=getchar();
if(ch=='.'){ch=getchar();while(ch<='9'&&ch>='0') t+=d*(ch^48),d*=0.1,ch=getchar();}
t=(f?-t:t);
}
template<typename T,typename... Args>inline void read(T& t,Args&... args){read(t); read(args...);}
char sr[1<<21],z[20];int C=-1,Z=0;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
inline void print(register int x)
{
if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
while(z[++Z]=x%10+48,x/=10);
while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
void file()
{
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
#endif
}
inline void chktime()
{
#ifndef ONLINE_JUDGE
cout<<(clock()-t)/1000.0<<'\n';
#endif
}
#ifdef mod
ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x%mod) if (y&1) ret=ret*x%mod;return ret;}
ll inv(ll x){return ksm(x,mod-2);}
#else
ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x) if (y&1) ret=ret*x;return ret;}
#endif
// inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
}
using namespace my_std;
int n,m;
ll K;
int F,T;
struct Matrix
{
ll a[sz][sz];
Matrix(){rep(i,1,n) rep(j,1,n) a[i][j]=0;}
void init(){rep(i,1,n) a[i][i]=1;}
};
inline Matrix operator * (const Matrix &a,const Matrix &b)
{
Matrix ret;
rep(i,1,n) rep(k,1,n) rep(j,1,n) (ret.a[i][j]+=a.a[i][k]*b.a[k][j]%mod)%=mod;
return ret;
}
Matrix a,s[13],S;
void ksm(ll y)
{
Matrix ret;ret.init();
for (;y;y>>=1,S=S*S) if (y&1) ret=ret*S;
S=ret;
}
int p[5];
int main()
{
file();
read(n,m,F,T,K);++F,++T;
int x,y;
rep(i,1,m) read(x,y),++x,++y,a.a[x][y]++,a.a[y][x]++;
rep(i,1,12) s[i]=a;
read(m);
while (m--)
{
read(x);
rep(i,0,x-1) read(p[i]),++p[i];
rep(i,1,12)
{
y=p[i%x];
rep(j,1,n) s[i].a[j][y]=0;
}
}
S.init();
rep(i,1,12) S=S*s[i];
ksm(K/12);
rep(i,1,K%12) S=S*s[i];
cout<<S.a[F][T];
return 0;
}
T4
事情开始变得恶心起来。
这题我会专门写一篇博客的,等下放上来。
update: https://www.cnblogs.com/p-b-p-b/p/10542289.html
T5
暂时还不会,以后搞。