codeforces good bye 2018
codeforces good bye 2018
good bye candidate master
2018年的最後一場cf
感覺打完我又用rating換了一大波rp
T1
題意: 給出三個數\(r\),\(b\),\(y\),定義\(a\),\(b\),\(c\)是分別小於等於這三個數且滿足\(a+2==b+1=c\)
求\(a+b+c\)的最大值
題解: 日常讀錯題,zz的我考場上沒看清楚題面以為是要求\(a>b>c\),樣例沒測就交了。。。WA*1
實際上只要列舉一下\(a\),\(b\),\(c\)那個取了最大值就好了,,,要滿足答案最大,一定有一個是取最大值的
程式碼:
#include<map> #include<queue> #include<cmath> #include<bitset> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; int a,b,c; int main(){ // freopen("1.in","r",stdin); scanf("%d%d%d",&a,&b,&c); if(a+1<=b&&a+2<=c) printf("%d\n",3*a+3); else if(b<=a+1&&b+1<=c) printf("%d\n",3*b); else printf("%d\n",3*c-3); return 0; }
T2
題意:給出\(n\)個標誌物座標\((x_i,y_i)\)以及\(n\)個線索\((a_i,b_i)\),要把標誌物和線索兩兩匹配使得所有\((x_i+a[p_i],y_i+a[y_i])\)相等
題解:本來是想要先列舉第一個座標所匹配的線索,然後判斷是否存在匹配方案使得寶藏座標等於枚舉出的座標,這樣時間複雜度\(n^2logn\)應該也能過,雖然有點zz
然而其實這道題可以\(nlogn\)過:要想每個都相等,對於最小的\(x\)座標,一定要給他最大的\(a\)來補,對於\(y\)也是一樣。。
這樣的話sort一遍就好了
程式碼:
#include<map> #include<queue> #include<cmath> #include<bitset> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; const int maxn=1100; struct node{ int x,y; }e[maxn],t[maxn]; int n; bool cmp(node x,node y){return x.x<y.x;} bool Cmp(node x,node y){return x.y<y.y;} int main(){ // freopen("1.in","r",stdin); scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d%d",&e[i].x,&e[i].y); for(int i=1;i<=n;i++) scanf("%d%d",&t[i].x,&t[i].y); sort(e+1,e+n+1,cmp); sort(t+1,t+n+1,cmp); printf("%d ",e[1].x+t[n].x); sort(e+1,e+n+1,Cmp); sort(t+1,t+n+1,Cmp); printf("%d\n",e[1].y+t[n].y); return 0; }
T3
題意:n個元素的環,編號為1~n,一個球一開始在1,每次可以順時針移動k步,每移動到一個點上就會產生這個點的編號點貢獻,再次到1時停止,問對於所有k,能產生哪幾種不同的總貢獻
題解:對於n的每一個約數都統計一下就好了,不要忘記去重
程式碼:
#include<map>
#include<queue>
#include<cmath>
#include<bitset>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=1e7+100;
int n,tot;
ll p[maxn];
inline int work(int n,int x){
ll tmp=n/x;
p[++tot]=n*(tmp-1)/2+tmp;
}
int main(){
// freopen("1.in","r",stdin);
scanf("%d",&n);
for(int i=1;i*i<=n;i++)
if(n%i==0){
work(n,i),work(n,n/i);
}
sort(p+1,p+tot+1);p[0]=-1;
for(int i=1;i<=tot;i++)
if(p[i]!=p[i-1]) printf("%I64d ",p[i]);
printf("\n");
return 0;
}
T4
題意:把n個元素的所有排列按字典序頭尾相接,形成一個長為\(n*n!\)的數列a,問有多少對\(l,r\)滿足
\[ a[l]+a[l+1]+...+a[r-1]+a[r]=n*(n+1)/2 \]
題解:分析了一下樣例,很顯然的可以發現只有當\(l,r\)代表的是一個排列的時候才會等於\(n*(n+1)/2\),就考慮對於每個排列,他對答案的貢獻
想象對於每個答案排列,他都可以分為兩部分,一部分屬於\(a\)中的前一個排列末尾,一個屬於後一個排列開頭,因為排列總數是\(n!\),對於一個排列分法有\(n\)種,所以總方案應是\(n*n!\)
但是這些方案中有一些是不合法的,比如:(n=5,設\(x\)是前一個末尾,y是後一個開頭)
\[ x=\{4,2\},y=\{1,3,5\} \]
顯然,完整的前一個應該是\(\{1,3,5,4,2\}\),但是我們發現,後一個是不會合法的,因為他要滿足比前一個大,但是前一個的最後兩位(即\(x\))是單減的,也就是說沒有比\(x\)大的了。
那麼我們列舉所有長度的單減序列,長度為\(i\)的單減序列總數就等於在一個\(\{n,n-1,n-2,...,1\}\)的序列裡挑\(i\)個數,即\(C(n,i)\),對於每個單減序列\(x\),他的\(y\)是可以隨便填的(這裡的x,y還是上面的定義),方案總數\((n-i)!\)
然後就沒有然後了,總方案數\(n*n!\),不合法方案數\(\sum_{i=1}^n{C(n,i)*(n-i)!}\),合法方案就是:
\[ ans=n*n!-\sum_{i=1}^n{C(n,i)*(n-i)!} \]
如果你沒有和zz的nianheng一樣在手算時zz地把\(4!\)算成\(16\),你就能馬上A掉這道題了
程式碼:
#include<map>
#include<queue>
#include<cmath>
#include<bitset>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=1e7+100,P=998244353;
int n;
ll jc[maxn],ans;
void ycl(){
jc[0]=1;
for(int i=1;i<=n;i++)
jc[i]=jc[i-1]*i%P;
}
inline ll poww(ll x,ll y){
ll base=1;
while(y){
if(y&1) base=base*x%P;
x=x*x%P;
y>>=1;
}
return base;
}
inline ll C(int n,int m){
return jc[n]*poww(jc[m],P-2)%P*poww(jc[n-m],P-2)%P;
}
int main(){
// freopen("1.in","r",stdin);
scanf("%d",&n);
ycl();
for(int i=1;i<=n;i++)
ans=(ans+C(n,i)*jc[n-i]%P)%P;
ans=(jc[n]*n%P-ans)%P;
printf("%I64d\n",(ans+1)%P);
return 0;
}
感想
失誤辣麼多,我還是太蒻了啊