3.14雜題選講
強烈譴責這次的出題人把難度搞這麽高,讓我這個菜雞怎麽活……
T1
非常顯然的思路是01分數規劃,然後就不會做了(大霧
考慮\(a\)小的可以連接到\(a\)大的任務上一起做,那麽顯然也可以把任務按\(a\)排序後相同的放在一起分組。
然後就可以開心快樂地DP了。
設\(dp_{i,j}\)表示前\(i\)組裏有\(j\)個記入答案,所能得到的最小權值(權值就是01分數規劃搞出來的東西)。
於是有轉移方程:
\[
dp_{i,j}=\max\{dp_{i-1,j-k}+W_{i,k}\}
\]
其中\(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×é£?óDj??óDD§μ?£?μ?μ?μ?×?′óè¨?μ // 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\)
然後暴力枚舉分界點即可。
復雜度似乎很大,但數據隨機,也就這麽跑過去了。
#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
事情開始變得惡心起來。
這題我會專門寫一篇博客的,等下放上來。
T5
暫時還不會,以後搞。
3.14雜題選講