Educational Codeforces Round 71 (Rated for Div. 2)
C. Gas Pipeline
这道题目贪心边界比较多,所以我直接写了 \(DP\) ,设 \(dp[i][0/1]\) 表示当前修到第 \(i\) 段管道, \(0\) 是低高度, \(1\) 是高高度的最小花费。
转移非常简单,不过需要注意的是从高处往低处转移的时候,这次加的花费是高的高度的花费,因为这次加的是上一个支柱的高度,然后最后只能是低高度的答案。
#include<bits/stdc++.h> #define ll long long using namespace std; const int N=2e5+100; const ll INF=1e15; ll t,n,a,b; char s[N]; ll dp[N][2]; inline void work() { for (int i=0;i<=n;i++) dp[i][0]=dp[i][1]=INF; dp[0][0]=0; for (int i=1;i<=n;i++) if (s[i]=='0') { dp[i][0]=min(dp[i-1][0]+a+b,dp[i-1][1]+a*2+b*2); dp[i][1]=min(dp[i-1][0]+a*2+b*2,dp[i-1][1]+a+b*2); } else { dp[i][0]=INF; dp[i][1]=min(dp[i-1][0]+a*2+b*2,dp[i-1][1]+a+b*2); } return ; } int main() { scanf("%lld",&t); while (t--) { scanf("%lld%lld%lld",&n,&a,&b); scanf("%s",s+1); work(); printf("%lld\n",dp[n][0]+b); } return 0; }
D. Number Of Permutations
这道题目是一个比较简单的组合数学题目。
首先,全部方案 \(=\) 第一个元素是所组成的数列是单调不减的方案数 \(+\) 第二个元素是所组成的数列是单调不减的方案数 \(-\) 第一个元素是所组成的数列是单调不减的方案数并且第二个元素是所组成的数列是单调不减的方案数。
然后你就会发现,前两个很好求,只需要用一下排列组合和乘法原理就可以了。
第一个元素是所组成的数列是单调不减的方案数就是第一个元素的每个元素出现的次数的阶乘相乘。
第二个元素同理。
求第三个方案数的时候 \(ZZ\) 了,其实只需要 \(sort\) 一遍,按照第一个元素为第一关键字第二个元素为第二关键字从小到大进行排序,然后判断第二个元素是否递增,如果不递增答案就为 \(0\) ,考虑什么样的两个二元组可以互换,只有第一个元素和第二个元素完全相同的才可以互换,所以我们只需要统计一下每个二元组出现的次数的阶乘然后全部相乘就可以了。
但是在写的时候却炸了,以后要用写离散化的方法统计。
#include<bits/stdc++.h> #define pii pair<int,int> #define mp make_pair #define one first #define two second #define ll long long const ll MOD=998244353; const int N=3e5+100; using std::pair; using std::make_pair; int n; ll ans; int tp[N]; pii p[N]; ll mul[N],Ans[N]; inline void work() { for (int i=1;i<=n;i++) if (tp[i]!=0) Ans[i]=mul[tp[i]]; ll now=1; for (int i=1;i<=n;i++) if (Ans[i]) now=Ans[i]*now%MOD; ans=(ans+now)%MOD; return ; } inline bool cmp(pii a,pii b) { if (a.one!=b.one) return a.one<b.one; return a.two<b.two; } inline void pre() { mul[1]=1; for (int i=2;i<=n;i++) mul[i]=mul[i-1]*i%MOD; return ; } int main() { scanf("%d",&n); pre(); for (int i=1;i<=n;i++) { int x,y; scanf("%d%d",&x,&y); p[i]=mp(x,y); tp[x]++; } work(); memset(tp,0,sizeof(tp)); memset(Ans,0,sizeof(Ans)); for (int i=1;i<=n;i++) tp[p[i].two]++; work(); sort(p+1,p+n+1,cmp); bool q=1; for (int i=2;i<=n;i++) if (p[i].two<p[i-1].two) { q=0; break; } if (q) { ll now=1; for (int i=1;i<=n;i++) { int k=i; while (p[k]==p[k+1]) k++; now=now*mul[k-i+1]%MOD; i=k; } ans=(ans-now+MOD)%MOD; } printf("%lld\n",(mul[n]-ans+MOD)%MOD%MOD); return 0; }