C. Chef Monocarp
这道题目给的tag实在是多,dp,二分图匹配,最小费用流都能写,反正由于数据量比较小,所以被各路神仙用各种方法过穿了,这里只写一下我看到的dp写法
dp[i][j]表示在排好序的a[i]数组中拿去i个元素且遍历到第j位时的状态,应该有如下转移方程
$$dp[i][j]=min(dp[i-1][j-1]+ \left\vert a[i]-j \right\vert,dp[i][k](k\in[1,j-1]))$$
由于两个子元素不在一个阶层,所以dp[i][j]应该在自己的上一层被更新一次,之后再和自己同一阶层的靠前元素进行比较
#include<cstdio> #include<algorithm> #include<map> #include<set> #include<vector> #include<iostream> #include<cmath> #include<cstring> #include<string> using namespace std; #define rep(i,a,n) for (int i=a;i<n;i++) #define per(i,a,n) for (int i=n-1;i>=a;i--)kjh #define pb push_back #define mp make_pair #define all(x) (x).begin(),(x).end() #define fi first #define se second #define SZ(x) ((int)(x).size()) typedef vector<int> VI; typedef long long ll; typedef pair<int,int> PII; typedef double db; const ll mod=1000000007; const ll INF=0x3f3f3f3f3f3f3f3f; const int inf=0x3f3f3f3f; /* mt19937 mrand(random_device{}()); int rnd(int x) { return mrand() % x;}*/ ll powmod(ll a,ll b) {ll res=1;a%=mod; for(;b>0;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;} ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;} ll inv(ll a){return (powmod(a,mod-2)+mod)%mod;} template<typename T>inline void read(T &x) { T f=1;x=0;char c; for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-1; for(;isdigit(c);c=getchar())x=x*10+(c^48); x*=f; } const int N=4e2+50; //set<pair<string,int> > st; //状态转移方程 dp[i][j]=min(dp[i-1][j-1],dp[i][k]); int _; int dp[N][N],a[N]; int main() { for(scanf("%d",&_);_;_--){ int m; cin>>m; memset(dp,0x3f,sizeof dp); rep(i,0,m) scanf("%d",a+i); sort(a,a+m); dp[0][0]=0; rep(i,0,m+1) { rep(j,0,2*m){ dp[i][j+1]=min(dp[i][j],dp[i][j+1]); if(i<m) dp[i+1][j+1]=dp[i][j]+abs(a[i]-j-1); } } cout<<dp[m][2*m]<<endl; } }
D. Minimal Height Tree
模拟,计算每一层能够存下的最多节点,存不下就depth++,进入下一层
#include<cstdio> #include<algorithm> #include<map> #include<set> #include<vector> #include<iostream> #include<cmath> #include<cstring> #include<string> using namespace std; #define rep(i,a,n) for (int i=a;i<n;i++) #define per(i,a,n) for (int i=n-1;i>=a;i--)kjh #define pb push_back #define mp make_pair #define all(x) (x).begin(),(x).end() #define fi first #define se second #define SZ(x) ((int)(x).size()) typedef vector<int> VI; typedef long long ll; typedef pair<int,int> PII; typedef double db; const ll mod=1000000007; const ll INF=0x3f3f3f3f3f3f3f3f; const int inf=0x3f3f3f3f; /* mt19937 mrand(random_device{}()); int rnd(int x) { return mrand() % x;}*/ ll powmod(ll a,ll b) {ll res=1;a%=mod; for(;b>0;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;} ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;} ll inv(ll a){return (powmod(a,mod-2)+mod)%mod;} template<typename T>inline void read(T &x) { T f=1;x=0;char c; for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-1; for(;isdigit(c);c=getchar())x=x*10+(c^48); x*=f; } const int N=2e5+50; //set<pair<string,int> > st; int a[N]; int _; int main() { for(scanf("%d",&_);_;_--){ int n; cin>>n; rep(i,0,n) scanf("%d",a+i); int root=1; int cnt=1,depth=1,nxt=0,pre=0; rep(i,1,n){ if(a[i]>pre||--root){ nxt++; pre=a[i]; // cout<<1<<endl; } else{ depth++; root=nxt; nxt=1; pre=a[i]; // cout<<2<<endl; } } cout<<depth<<endl; } }
E. Make It Increasing
从这一题又学到了一个新的模型,如何将一个序列快速变成升序列,构造+二分
如果是处理非完全上升序列,就不用对a的元素进行预处理
#include<cstdio> #include<algorithm> #include<map> #include<set> #include<vector> #include<iostream> #include<cmath> #include<cstring> #include<string> using namespace std; #define rep(i,a,n) for (int i=a;i<n;i++) #define per(i,a,n) for (int i=n-1;i>=a;i--)kjh #define pb push_back #define mp make_pair #define all(x) (x).begin(),(x).end() #define fi first #define se second #define SZ(x) ((int)(x).size()) typedef vector<int> VI; typedef long long ll; typedef pair<int,int> PII; typedef double db; const ll mod=1000000007; const ll INF=0x3f3f3f3f3f3f3f3f; const int inf=0x3f3f3f3f; /* mt19937 mrand(random_device{}()); int rnd(int x) { return mrand() % x;}*/ ll powmod(ll a,ll b) {ll res=1;a%=mod; for(;b>0;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;} ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;} ll inv(ll a){return (powmod(a,mod-2)+mod)%mod;} template<typename T>inline void read(T &x) { T f=1;x=0;char c; for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-1; for(;isdigit(c);c=getchar())x=x*10+(c^48); x*=f; } const int N=5e5+50; //set<pair<string,int> > st; int a[N],b[N]; int m,n; int cal(int l,int r,int mi,int mx){ vector<int> ve; rep(i,l,r) if(a[i]>=mi&&a[i]<=mx){ auto it=upper_bound(ve.begin(),ve.end(),a[i]); if(it==ve.end()) ve.push_back(a[i]); else *it=a[i]; } return ve.size(); } int main() { cin>>m>>n; rep(i,0,m){ scanf("%d",a+i); a[i]-=i; } rep(i,0,n){ scanf("%d",b+i); --b[i]; } int ans=m-n; if(!n) ans-=cal(0,m,-1e9,1e9); else { ans-=cal(0,b[0],-1e9,a[b[0]]); ans-=cal(b[n-1]+1,m,a[b[n-1]],1e9); rep(i,0,n-1){ if(a[b[i]]>a[b[i+1]]){ cout<<-1<<endl; return 0; } ans-=cal(b[i]+1,b[i+1],a[b[i]],a[b[i+1]]); } } cout<<ans<<endl; }
浙公网安备 33010602011771号