1. 程式人生 > >codeforces good bye 2018

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;
}

感想

失誤辣麼多,我還是太蒻了啊