1. 程式人生 > >雜題選講 DAY1

雜題選講 DAY1

queue set ide 包含 要花 tin SHH temp a+b

T1 【FJOI2016】建築師

題面:

H【FJOI2016】建築師
時間限制 : - MS 空間限制 : - KB 評測說明 : 1s 256m
問題描述

小 Z 是一個很有名的建築師,有一天他接到了一個很奇怪的任務:在數軸上建 n 個建築,每個建築的高度是 1 到 n 之間的一個整數。

小 Z 有很嚴重的強迫癥,他不喜歡有兩個建築的高度相同。另外小 Z 覺得如果從最左邊(所有建築都在右邊)看能看到 A個建築,從最右邊(所有建築都在左邊)看能看到 B 個建築,這樣的建築群有著獨特的美感。現在,小 Z 想知道滿足上述所有條件的建築方案有多少種?

如果建築 i 的左(右)邊沒有任何建造比它高,則建築 i 可以從左(右)邊看到。兩種方案不同,當且僅當存在某個建築在兩種方案下的高度不同。

輸入格式

第一行一個整數 T,代表 T 組數據。
接下來 T 行,每行三個整數 n,A,B

輸出格式

對於每組數據輸出一行答案 mod10^9+7。

樣例輸入 1

2
3 2 2
3 1 2

樣例輸出 1

2
1

樣例輸入 2

5
1 1 1
2 1 1
4 3 1
10 2 2
8 6 4

樣例輸出 2

1
0
3
219168
0

提示

對於 10% 的數據 : 1≤n≤10
對於 20% 的數據 : 1≤n≤100
對於 40% 的數據 : 1≤n≤50000, 1≤T≤5
對於 100%的數據 :1≤n≤50000, 1≤A,B≤100, 1≤T≤200000



題解:

由於高度為\(N\)的建築物肯定不會被擋住,將這個建築作為分水嶺,將左右兩邊分開為\(A+B-1\)

個部分;

顯然我們需要考慮將這\(N-1\)個人放在\(A+B-2\)個桌子上,這就是第一類斯特林數;

我們考慮可以將剩下的建築分為\(A-1\)\(B-1\)兩部分,於是這樣的方案數可通過組合數求出;

\(code:\)

#include<cstdio>
#include<iostream>
#include<ctype.h>
#include<cstring>
#include<vector>
#include<cmath>
#include<map>
#include<algorithm>
#define reint register int
#define ll long long
#define rell register ll
using namespace std;

char buf[1<<20],*p1,*p2;
inline char gc()
{
//    return getchar();
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin))==p1?0:*p1++;
}

template<typename T>
inline void read(T &x)
{
    char tt;
    bool flag=0;
    while(!isdigit(tt=gc())&&tt!='-');
    tt=='-'?(flag=1,x=0):(x=tt-'0');
    while(isdigit(tt=gc())) x=(x<<1)+(x<<3)+(tt^'0');
    if(flag) x=-x;
}

const int mod=1e9+7;
inline ll mul(ll a,ll b){return a*b<mod?a*b:a*b%mod;};
inline ll add(ll a,ll b){return a+b<mod?a+b:a+b-mod;};

ll c[202][202],s[50002][202];
void sent()
{
    s[0][0]=1;
    for(rell i=1;i<=50001;i++)
    for(rell j=1;j<=200;j++)
    s[i][j]=add(s[i-1][j-1],mul(i-1,s[i-1][j]));
    
    c[0][0]=1;
    for(rell i=1;i<=201;i++)
    for(rell j=0;j<=i;j++)
    c[i][j]=j?add(c[i-1][j],c[i-1][j-1]):1;
}

ll t,n,a,b;
int main()
{
    sent();
    read(t);
    while(t--)
    {
        read(n),read(a),read(b);
        printf("%lld\n",mul(s[n-1][a+b-2],c[a+b-2][a-1]));
    }
}

T2 【CERC2017】旅遊指南

題面:

I【CERC2017】旅遊指南
時間限制 : 20000 MS 空間限制 : 565536 KB SPJ 評測說明 : 1s,512m
問題描述

給定一張n個點,m條雙向邊的無向圖。

你要從1號點走到n號點。當你位於x點時,你需要花1元錢,等概率隨機地買到與x相鄰的一個點的票,只有通過票才能走到其它點。

每當完成一次交易時,你可以選擇直接使用那張票,也可以選擇扔掉那張票然後再花1元錢隨機買另一張票。註意你可以無限次扔票。

請使用最佳的策略,使得期望花的錢數最少。

輸入格式

第一行包含兩個正整數n,m(1<=n,m<=300000),表示點數和邊數。

接下來m行,每行兩個正整數u,v(1<=u,v<=n),表示一條雙向邊。

輸入數據保證無重邊、無自環,且1號點一定可以走到n號點。

輸出格式

輸出一行一個實數,即最少的期望花費,當絕對或者相對誤差不超過10^{-6}時視為正確。

樣例輸入 1

5 8
1 2
1 3
1 4
2 3
2 4
3 5
5 4
2 5

樣例輸出 1

4.1111111111

樣例輸入 2

4 4
1 2
1 3
2 4
3 4

樣例輸出 2

3.0000000000



題解:

好題啊!妙啊!

我們設定狀態F[i]為從i點到終點所花錢數最少的期望,那麽顯然可以得到:

\(F[p]=\frac{\sum\ min(F[p],F[x_i])}{deg[p]}+1;\)

移項得:

\(deg[p]*F[p]=\sum min(F[p],F[x_i])+deg[p];\)

我們設在取最小值的過程中使用了\(a\)\(F[x_i]\),那麽:

\(deg[p]*F[p]=(deg[p]-a)*F[p]+a*F[x_i]+deg[p];\)

\(F[p]*a=F[x]*a+deg[p];\)

\(F[p]=\frac{a*F[x]+deg[p]}{a};\)

初始狀態\(F[N]=0\),因為我們默然最開始所有的取最小處都是選擇的\(F[x]\),所以所得期望一定大於等於結果,通過小值去更新,即可使其接近或等於答案,這個貪心的過程我們註意到類似於迪傑斯特拉;

\(code:\)

#include<cstdio>
#include<iostream>
#include<ctype.h>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<map>
#include<algorithm>
#define reint register int
#define ll long long
#define ld double
#define rell register ll
using namespace std;

char buf[1<<20],*p1,*p2;
inline char gc()
{
//    return getchar();
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin))==p1?0:*p1++;
}

template<typename T>
inline void read(T &x)
{
    char tt;
    bool flag=0;
    while(!isdigit(tt=gc())&&tt!='-');
    tt=='-'?(flag=1,x=0):(x=tt-'0');
    while(isdigit(tt=gc())) x=(x<<1)+(x<<3)+(tt^'0');
    if(flag) x=-x;
}

struct node{
    int x;
    ld len;
    inline node(int a=0,ld b=0.0)
    {x=a,len=b;}
    inline bool operator<(node a)const
    {return len>a.len;}
};

const int maxn=300002;
int n,m,deg[maxn];
int a[maxn];
vector<int>G[maxn];
priority_queue<node>q;
ld f[maxn],sum[maxn];
bool book[maxn];
void djs()
{
    f[n]=0.0;q.push(node(n,0.0));
    while(!q.empty())
    {
        int x=q.top().x;q.pop();
        if(book[x]) continue;
        book[x]=1;
//      printf("%d--\n", G[x].size()-1);
        for(reint i=G[x].size()-1;i>=0;i--)
        {
            int p=G[x][i];
            if(book[p]) continue;
            a[p]++;sum[p]+=f[x];
            f[p]=(sum[p]+deg[p])/a[p];
            q.push(node(p,f[p]));
        }
    }
}

int main()
{
    read(n),read(m);
    for(reint i=1;i<=m;i++)
    {
        int x,y;
        read(x),read(y);
        G[x].push_back(y);
        G[y].push_back(x);
        deg[x]++;deg[y]++;
    }
    djs();
    printf("%.10lf",f[1]);
}

T3 【HAOI2017】供給側改革

題面:

J【HAOI2017】供給側改革
時間限制 : - MS 空間限制 : - KB 評測說明 : 1s,256m
問題描述

Anihc國提高社會生產力水平.落實好以人民為中心的發展思想。決定進行供給側結構性改革。

為了提高供給品質.你調查了某個產業近來n個時期的供求關系平衡情況.每個時期的情況都用0或1中的一個數字來表示.於是這就是—個長度為n的01字符串S。為了更好的了解這一些數據.你需要解決一些詢問.我們令data(l,r)表示:在字符串S中.起始位置在[l,r]之間的這些後綴之中,具有最長公共前綴的兩個後綴的最長公共前綴的長度。

對於每一個詢問L,R.求

ans=∑data(i,R) L≤i<R

由於你其實根本沒有時間調查,所以這些數據都是亂編的,即串S中的每一位都是在0和1之間隨機產生的。

輸入格式

第一行2個整數n,Q,表示字符串的長度,以及詢問個數

接下來一行長度為n的一個01串S

接下來Q行,每行2個整數L,R.一個詢問L.R

輸出格式

共Q行.每行一個整數.表示對應詢問的答案。

樣例輸入 1

6 3
010110
2 5
1 6
1 2

樣例輸出 1

4
6
0

樣例輸入 2

20 20
01010011000001000111
1 3
6 13
5 10
3 6
3 6
6 16
8 18
1 4
11 15
3 13
1 19
7 10
10 13
3 9
4 17
1 18
2 20
1 20
2 19
1 20

樣例輸出 2

3
22
20
4
4
33
26
5
7
34
59
12
6
10
42
54
56
60
55
60

提示
數據點    n的規模    Q的規模
1    <= 20    <= 20
2    <= 20    <= 20
3    <= 100    <= 100
4    <= 100    <= 100
5    <= 5000    <= 5000
6    <= 5000    <= 5000
7    <= 100000    <= 100000
8    <= 100000    <= 100000
9    <= 100000    <= 100000
10    <= 100000    <= 100000

對於所有的數據保證:n <= 100000,Q<= 100000,1<=L<R<=n,01串隨機生成。



題解:

未做呢,待補待補;


T4 平衡的隊列

題面:

技術分享圖片

輸入格式

第一行,兩個空格間隔的整數N和K
接下來N行,每行一個K位二進制整數(已轉換成了十進制),表示第i頭奶牛的特征

輸出格式

一行,一個整數,表示最大的平衡區間的長度

樣例輸入

7 3
7
6
7
2
1
4
2

樣例輸出

4

提示

樣例說明:這個範圍是3到6,其中每個特征恰好出現了2次。


題解:

記錄每一位上的前綴和,\(Hash\)一下,加上\(map\)看前面有沒有一樣的;

\(code:\)

#include<cstdio>
#include<iostream>
#include<ctype.h>
#include<cstring>
#include<vector>
#include<cmath>
#include<map>
#include<algorithm>
#define reint register int
#define mod1 1000000007
#define mod2 998244353
#define ll long long
using namespace std;

char buf[1<<20],*p1,*p2;
inline char gc()
{
//    return getchar();
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin))==p1?0:*p1++;
}

template<typename T>
inline void read(T &x)
{
    char tt;
    bool flag=0;
    while(!isdigit(tt=gc())&&tt!='-');
    tt=='-'?(flag=1,x=0):(x=tt-'0');
    while(isdigit(tt=gc())) x=(x<<1)+(x<<3)+(tt^'0');
    if(flag) x=-x;
}

const int maxn=1e5+2;
int n,k;
ll hashh[maxn];
int sum[maxn][32];
map<ll,int>book;
int main()
{
    read(n),read(k);
    for(reint i=1;i<=n;i++)
    {
        ll x;
        read(x);
        for(int j=0;j<k;j++)
        sum[i][j]=(x>>j&1)+sum[i-1][j];
    }
    
//  for(int i=1;i<=n;i++,putchar(10))
//  for(int j=0;j<k;j++)
//  printf("%d ",sum[i][j]);
    
    for(reint i=1;i<=n;i++)
    {
        int tmp=sum[i][0];
        for(reint j=0;j<k;j++)
        sum[i][j]-=tmp;
    }
    
    for(reint i=0;i<=n;i++)
    for(reint j=0;j<k;j++)
    hashh[i]=hashh[i]*mod1+1ll*(1ll*sum[i][j]+mod2);
    
    int ans=0;
    for(reint i=0;i<=n;i++)
    {
        if(!book[hashh[i]]) book[hashh[i]]=i+1;
        else ans=max(ans,i-book[hashh[i]]+1);
    }
    printf("%d",ans);
}

T5 [JLOI2015 DAY1]有意義的字符串

題面:

L [JLOI2015 DAY1]有意義的字符串
時間限制 : - MS 空間限制 : 165536 KB 技術分享圖片評測說明 : 1S
問題描述

技術分享圖片

輸入格式

一行三個整數b,d,n。

輸出格式

一行一個數表示模7528443412579576937 之後的結果。

樣例輸入 1

1 5 9

樣例輸出 1

76

樣例輸入 2

11 125 6715504

樣例輸出 2

1499928102740042526

提示

技術分享圖片


題解:

本題面向數據編程=_=;

首先,我們可以發現,原式可以轉換為求:

\((\frac{b+\sqrt{d}}{2})^n+(\frac{b-\sqrt{d}}{2})^n-(\frac{b-\sqrt{d}}{2})^n\)

這個式子,我們又觀察一下可以發現:

\(X_1=(\frac{b+\sqrt{d}}{2}),X_2=(\frac{b-\sqrt{d}}{2})\)

這是一個二次方程的兩個根:

\(X^2+b*X-\frac{b^2-d}{4}=0\)

然後呢,對我們要求的前半部分,是一個整數,後半部分值域為\((-1,0]\),這個由數據範圍可得;
我們設:

\(F(n)=X_1^n+X_2^n;\)

那麽易得:

\(X_1^n+X_2^n=(X_1+X_2)(X_1^{n-1}+X_2^{n-2})-X_1*X_2^{n-1}-X_2*X_1^{n-1}=(X_1+X_2)(X_1^{n-1}+X_2^{n-2})-(X_1*X_2)(X_1^{n-2}+X_2^{n-2})\)

由韋達定理:

\(X_1+X_2=b,X_1*X_2=\frac{d-b^2}{4};\)

那麽我們要求的就變成了:

\(F(n)=F(n-1)*b+F(n-2)*(\frac{d-b^2}{4});\)

這個顯然可以用矩陣快速冪優化;

考慮後半部分,我們只要看看它有沒有可能做出值為-1的貢獻即可(當且僅當\(n\)為奇數,且\(d!=b*b\))

\(code:\)

#include<cstdio>
#include<iostream>
#include<ctype.h>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<map>
#include<algorithm>
#define reint register int
#define ll long long
#define ld double
#define rell register ll
#define mod 7528443412579576937ul
using namespace std;

char buf[1<<20],*p1,*p2;
inline char gc()
{
//    return getchar();
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin))==p1?0:*p1++;
}

template<typename T>
inline void read(T &x)
{
    char tt;
    bool flag=0;
    while(!isdigit(tt=gc())&&tt!='-');
    tt=='-'?(flag=1,x=0):(x=tt-'0');
    while(isdigit(tt=gc())) x=(x<<1)+(x<<3)+(tt^'0');
    if(flag) x=-x;
}
inline ll add(ll x,ll y){return x+y>=mod||x+y<0?x+y-mod:x+y;}
inline ll sub(ll x,ll y){return x-y<0?x-y+mod:x-y;}
inline ll mul(ll x,ll y){ll d=(ll)(x*(long double)y/mod+0.5);return sub(x*y,d*mod);}
struct arr{
    ll n,m;
    ll a[21][21];
    ll *operator[](int b){return a[b];}
    inline arr(ll c=0,ll d=0)
    {
        memset(a,0,sizeof(a));
        n=c,m=d;
    }
    arr operator*(arr b) const
    {
        arr c;
        c.n=n;c.m=b.m;
        for(reint i=0;i<n;i++)
        for(reint j=0;j<c.m;j++)
        for(reint k=0;k<m;k++)
        c[i][j]=add(c[i][j],mul(a[i][k],b[k][j]));
        return c;
    }
    arr operator*=(arr a){
        *this=*this*a;
        return *this;
    }
    arr operator^(ll b)
    {
        arr ans;
        ans=arr(n,m);
        for(reint i=0;i<n;i++)
        ans[i][i]=1;
        while(b)
        {
            if(b&1ul) ans*=*this;
            *this*=*this;
            b>>=1ul; 
        }
        return ans;
    }
};

ll b,d,n;
arr aa,bb;
int main()
{
    read(b),read(d),read(n);
    if(!n) puts("1"),exit(0);
    
    aa=arr(1,2);bb=arr(2,2);
    aa[0][0]=b,aa[0][1]=2;
    bb[0][0]=b,bb[0][1]=1;
    bb[1][0]=(d-b*b)/4,bb[1][1]=0;
    aa*=bb^(n-1);
    printf("%lld",sub(aa[0][0],!(n&1ul)&&(d!=b*b)));
}

雜題選講 DAY1