1. 程式人生 > >【浮*光】 #noip模擬10.24#

【浮*光】 #noip模擬10.24#

我真的.真的..真的...炒雞炒雞高興的說!

因為,在noip前16天,我快要退役的時候,居然 ...

AK辣 ~\(≧▽≦)/~ 啦啦啦

好吧我承認我是 295分 ......

而且這麼高是因為第二題抄了 斜率優化 的模板,

第三題和 LRZ大神 討論了並且抄了他的dfs ......

可能是這套題比較符合我的口味吧?

而且很快的切掉了第一題...特別順利的說!

反正無論如何,就是很高興啊、很高興啊 ovo

感謝 wuli 大男神 && ZJ && Rin && 各大男神 qwq

 目錄

【T1】聽寫(dictation)

  • 老師給大家一種全新的語言,要你來鑑別它們是不是合法的。

1.一個句子由主語、謂語和賓語按先後順序排列而成,

   缺少其中任何一個成分都不是這種語言;

2.語言中存在兩種從句:主語從句和定語從句;

3.對於主語從句,從句裡可以有新的從句,

   從句只可替代應有的部分,所以並不會出現形式主語等;

4.對於有定語從句的句子,定語從句只能修飾賓語(放在賓語後) ,

   而且其修飾的賓語應該省略,定語從句裡也可以有新的從句。

  • 為了簡化問題,用 z 代表主語,w 代表謂語,b 代表賓語。

【輸入格式】

第一行是資料組數 T。接下來 T 行表示 T 段聽寫的內容,

注意一段聽寫內容中可能有多句話, 但句與句之間沒有標點。

【輸出格式】

對於每組資料,輸出一或兩行。如果當前這段聽寫內容出現了問題,

那麼輸出“Yes”,否則輸出“No” ,並在接下來的一行裡輸出這段話中從句的總個數。

【樣例輸入】

  • 3
  • zwz
  • zwbzw
  • zwbwb

【樣例輸出】

  • Yes
  • Yes
  • No
  • 1

【標籤】找規律 + 分類討論 + 模擬

貌似是獨創方法???好像dalao和官方題解都不是這樣寫的來著...

難道是我終於聰明瞭一回???哈哈哈......qwq

方法就是,找規律,發現原串可以分成:

  • zwb wb w zwb w zwb w zwb w zwb w zw zwb wb wb wb wb w zwb
  • w zwb wb wb w zwb wb w zwb w zw zwb w zwb wb w zw zw zw zw zw
  • zw zwb wb w zwb wb wb w zw zwb (答案為 49)

為什麼這樣分?斷開所有的 ‘ w ’。並且是按照規律斷開。

【規律】如果是合法序列,‘ w ’ 的存在形態只可能是:

  •  w ; wb ; zw ; zwb 。

然後對應的分別構成 2, 1, 1, 0 個從句(按省略的z或b計算)。

這樣只要特判一下不可能的情況,順序掃一遍就行了....qwq。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<queue>
#include<vector>
#include<cmath>
#include<map>
#include<set>
using namespace std;
typedef long long ll;

//【聽寫】

//zwb wb w zwb w zwb w zwb w zwb w zw zwb wb wb wb wb w zwb 
//w zwb wb wb w zwb wb w zwb w zw zwb w zwb wb w zw zw zw zw zw 
//zw zwb wb w zwb wb wb w zw zwb

void reads(ll &x){ //讀入優化(正負整數)
    ll fx=1;x=0;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')fx=-1;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    x*=fx; //正負號
}

char ss[100019];

int main(){
    freopen("dictation.in","r",stdin);
    freopen("dictation.out","w",stdout);
    int n; scanf("%d",&n);
    for(int kase=1;kase<=n;kase++){
        scanf("%s",ss); int i=0,len=strlen(ss),ans=0,okk=true;
        if(ss[0]!='z'||ss[len-1]!='b')
            { printf("Yes\n"); continue; }
        while(i<len){
            if(ss[i]=='z'&&ss[i+1]=='w'&&ss[i+2]=='b') 
              {  i+=3; continue; }
            if(ss[i]=='z'&&ss[i+1]=='w'&&ss[i+2]=='w')
              {  printf("Yes\n"); okk=false; break; }
            if(ss[i]=='z'&&ss[i+1]=='w'&&ss[i+2]=='z') 
              {  i+=2; ans++; continue; } //填一個b
            if(ss[i]=='z') //z後面不是w,或者 zw 在末尾,都是不行的
              {  printf("Yes\n"); okk=false; break; }
            if(ss[i]=='w'&&ss[i+1]=='w') //兩個w不能相連
              {  printf("Yes\n"); okk=false; break; }
            if(ss[i]=='w'&&ss[i+1]=='b') //wb + z/w..
              {  i+=2; ans++; continue; }
            if(ss[i]=='w'&&ss[i+1]=='z') //w + z..
              {  i++; ans+=2; continue; }
            if(ss[i]=='w') //單獨的 w 在末尾,是不行的
              {  printf("Yes\n"); okk=false; break; }
            if(ss[i]=='b') //不可能存在單獨的b
              {  printf("Yes\n"); okk=false; break; }
        } if(okk==true) cout<<"No"<<endl<<ans<<endl;
    }
}

【T2】遙遠的金字塔(pyramid)

  • 在歷史課上,你有一個金字塔的側檢視。這個金字塔一共有 n 層,
  • 從下至上編號為 1至 n。除了第一層外,其餘層均被它底下的一層包含。
  • 即如果 xi,yi分別表示第 i 層的左、右端點,則對於任意的 i≥2,都有 xi≥xi-1,且 yi≤yi-1。
  • 每一層矩形的高度均為 1。 在整個側檢視中選擇恰好 k 個不相交的矩形 ,
  • 問這 k 個不相交的矩形覆蓋的面積最大是多少。

【輸入格式】

第一行兩個整數 n 和 k。第二至 n+1 行,

其中第 i+1 行兩個整數 xi和 yi,分別表示第 i 層金字塔的左右端點。

【輸出格式】

只包含一個整數,即最大覆蓋面積。

【樣例輸入】

  • 5 3
  • 1 6
  • 1 5
  • 3 5
  • 4 4
  • 4 4

【樣例輸出】

  • 15

【標籤】DP + 斜率優化 + 單調佇列維護單調性

......普通 DP 80分,就是這個式子:

  • f [ i ][ j ] = max( f [ k ][ j - 1 ] + ( y[ i ] - x [ i ] ) * ( i - ( k + 1 ) + 1 ) ) ;

然後我寫斜率優化坑了好久...結果只加上了15分...

好吧我確實是傻逼...要化除為乘才能AC2333...

具體分析過程看程式碼吧 ovo 註釋超詳細的 qwq

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<queue>
#include<vector>
#include<cmath>
#include<map>
#include<set>
using namespace std;
typedef long long ll;

//【遙遠的金字塔】

//f[i][j]表示已經到第i層(從下到上),已經選了j個矩形的max面積和。

//列舉包含i的矩形的最下層(編號小)的下一層k=( j-1 ~ i-1 )
//為什麼從j-1開始?因為如果一層選兩個矩形,一定不是最優。

//f[i][j]=max(f[k][j-1]+(y[i]-x[i])*(i-(k+1)+1));
//因為金字塔滿足包含關係,所以最短的一定是最上層的y[i]-x[i]。

//列舉k肯定會超時啦啦啦...所以嘗試一下單調佇列優化?

//f[i][j]=max(f[k][j-1]+a[i]*i-a[i]*k);

//f[i][j]=max(f[k][j-1]-a[i]*k) + a[i]*i;

//暫時把j這一維省略掉...f[i]=max(f[k]-a[i]*k)+a[i]*i;

//這東西好眼熟...有點像...斜率優化?

//yi-xi*k>=yk-xk*k (k=a[i])

//a[i]<=f[i]-f[k]/(i-k);我真的忘了斜率優化怎麼做的了...

//slop(i,k)=f[i]-f[k]/(i-k)?然後用單調佇列...?

//維護隊頭的可行性(對於每個新的i),隊尾的單調性...隊頭即為最優解。

void reads(ll &x){ //讀入優化(正負整數)
    ll fx=1;x=0;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')fx=-1;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    x*=fx; //正負號
}

ll f[20019][109],q[109][20019],a[20019],head[109],tail[109];

double slop(ll k1,ll k2,ll j){ return (double)(f[k2][j]-f[k1][j]); }

int main(){
    freopen("road.in","r",stdin);
    freopen("pyramid.out","w",stdout);
    ll n,m,x,y,ans=0; reads(n),reads(m);
    
    for(ll i=1;i<=n;i++) reads(x),reads(y),a[i]=y-x+1;

    for(ll j=0;j<=m;j++) head[j]=1,tail[j]=1,q[j][1]=0;

    for(ll i=1;i<=n;i++)
        for(ll j=min(i-1,m-1);j>=0;j--){ //↓↓維護隊頭可行性
        
            while(head[j]<tail[j]
                &&slop(q[j][head[j]],q[j][head[j]+1],j)
                    >(double)a[i]*(q[j][head[j]+1]-q[j][head[j]])) head[j]++;
            
            f[i][j+1]=f[q[j][head[j]]][j]-a[i]*q[j][head[j]]+a[i]*i; 
            //(q[j][head[j]]+1)~i行組成矩形,答案最優
            
            while(head[j+1]<tail[j+1]
                &&slop(q[j+1][tail[j+1]-1],q[j+1][tail[j+1]],j+1)*(i-q[j+1][tail[j+1]])
                    <slop(q[j+1][tail[j+1]],i,j+1)
                        *(q[j+1][tail[j+1]]-q[j+1][tail[j+1]-1])) tail[j+1]--;

            q[j+1][++tail[j+1]]=i; //↑↑↑需要將i入隊,但要保持佇列斜率單調性
        }

    for(ll i=1;i<=n;i++)
        for(ll j=1;j<=m;j++)
            if(ans<f[i][j]) ans=max(ans,f[i][j]);
    
    cout<<ans<<endl; return 0;
}

【T3】心靈治癒(heal)

  • “假設這裡有一條長軸,在 0 號位置有一個小球,它代表一個人來臨到這個世界,
  • 開始了他的人生道路。他將很多個人生境況,每個境況對人生可能產生多次影響。
  • 而對於每一次影響,它也許能幫助你前進,但如果你不能保持成功不驕傲,
  • 失敗不氣餒,那表面看起來的好的境況也許會讓你後退,因此一個人有可能會走到負數。
  • “而大部分境況的影響值是由你後天所決定的。如果你能好好認識與對待境況,
  • 它們就會讓你前進相應的影響值。否則,你可能會後退相應的影響值,或者待在原點。
  • “但是人類無法擺脫貪婪的特點,他們始終儘可能的前進。 但是,大家似乎都忽略了一點,
  • 那就是人生的終點其實就在 1 號點。許許多多的人由於境況影響值的原因,無法到達生命的
  • 終點,那他的一生就是不圓滿的。回到原點的前面,這大概就是生命的真諦吧。 ”羽點點頭。
  • “在生命終點的境況的影響永遠是最大的,它之前沒有哪一個境況的影響值是大於它的。
  • 因為在生命終點浮現在你腦海裡的永遠是對你最重要的東西。
  • 並且生命結束的方式和其影響值其實在你出生的時候就已經決定了。
  • “那麼從人生的起點到終點,成長羈絆的境況的影響值組合究竟有多少種情況呢?”

【輸入格式】

輸入檔案有且僅有一行,包括用空格分開的兩個整數 N 和 M。

N 表示一共有 N+1 個人生境況,M 表示生命終點的境況的影響值。

【輸出格式】

輸出有多少種境況的影響值的組合能滿足可以從人生起點走到終點。

由於答案可能很大,輸出它模 1000000007的值。注意,境況是按時間有序的。

【樣例輸入1】

  • 2 3

【樣例輸出1】

  • 8

【樣例輸入2】

  • 8 8

【樣例輸出 2】

  • 16711680

【樣例說明】

為了不影響【題目描述】的優美性,題意的進一步解釋將放在【樣例說明】中。

1.境況的總個數已經確定為 N+1,除了第 N+1 個境況,其他境況的影響值未知;

2.長軸表示人生的道路,每一個點對應人生的一個位置,長軸無限長,

但長軸與境況沒有關係,即任一境況可以在任意的位置發生,位置對境況沒有任何影響;

3.生命結束的方式,即第 N+1 個境況,它的影響值已經在出生時就給定為 M;

4.其他境況(第 1-N 個境況)的影響值不會大於第 N+1 個境況的影響值,

且其影響值一定是正的, 但在長軸上的效果是可以是負的,

後退即在當前位置減去這個境況的影響值到達新的位置;

5.每一個境況都會影響人生至少一次,同一個境況可以影響人生多次,

並且每一次對人生的影響效果(前進 或 後退 或 停在原地)可以不同;

6.長軸的點不一定都會經過,每一個境況會依次經過;

7.題目要求的是有多少種境況影響值的組合,使得在經歷了這些境況之後,

可以從生命起點到達生命的終點,境況具體怎麼影響人生可參見下面的解釋;

8.境況的影響值組合是一個長度為 N+1 的序列,第 i 個數代表第 i 個境況的影響值

(不需要輸出) ,注意:境況的影響值並不是該境況對人生產生影響的次數,

而是每一次該境況對人生產生影響效果時前進或後退的距離 。

9.境況是按時間有序的,即同樣的組合,不同的順序也分別計入答案。

對於樣例 1,這 8 種可能的 境況影響值組合 分別是:

(1, 1, 3), (1, 2, 3), (1, 3, 3), (2, 1, 3), (2, 2, 3), (2, 3, 3), (3, 1, 3), (3, 2, 3).

【標籤】題面理解 + 大膽猜想 + 質因數 +容斥原理

題意轉化為:a[n+1]=m,a[1~n]<m,求所有的數的最大公因數是1的方案數。

...一開始算錯了4^8...然後發現 8 8 真的就是 8^8-4^8...

(1)總數m^n。分解m=p1^k1*p2^k2*...*pt^kt,

        那麼選擇的數不能全部都是pi的倍數:- (m/pi)^n。

        但重複減掉了完全是pi*pj的倍數的情況(一共兩個質因子)。

(2)如果有兩個因子相乘的倍數pi*pj,+ (m/(pi*pj))^n。

(3)如果有三個因子相乘的倍數pi*pj*pk,

        先被減了3次,又被兩兩組合,加了3*(3-1)/2=3次。

        那麼還要 - (m/(pi*pj*pk))^n。

(4)如果有四個因子相乘的倍數pi*pj*pk*pl,

        先被減了4次,又被兩兩組合加了4*(4-1)/2=6次,

        還被三三組合減了4次,那麼還要再加一次 + (m/(pi*pj*pk*pl))^n。

(5)如果有五個因子相乘的倍數pi*pj*pk*pl*pt,

        先被減了5次,又被兩兩組合加了5*(5-1)/2=10次,

        被三三組合減了10次,被四四組合加了5次,

        還要減一次 - (m/(pi*pj*pk*pl*pt))^n

然後就發現了規律...不過好像容斥原理裡面本來就有這種定理吧??

質因子數相乘<10^15,所以質因子個數不會超過15個...

dfs就行...(我才不要說這個dfs是抄的 LRZ大神 的 qaq)

大概我能看懂題意,是因為我語文比較好吧???

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<queue>
#include<vector>
#include<cmath>
#include<map>
#include<set>
using namespace std;
typedef long long ll;

//【心靈治癒】

//a[n+1]=m,a[1~n]<m,求所有的數的最大公因數是1的方案數

//...一開始算錯了4^8...然後發現 8 8 真的就是 8^8-4^8...

//總數m^n。分解m=p1^k1*p2^k2*...*pt^kt,
//那麼這些數不能完全是pi的倍數:-(m/pi)^n。
//但重複減掉了完全是p1*p2的倍數的情況(一共兩個質因子)。

//如果有兩個因子相乘的倍數pi*pj,+(m/(pi*pj))^n。

//如果有三個因子相乘的倍數pi*pj*pk,
//先被減了3次,又被兩兩組合,加了3*(3-1)/2=3次。
//那麼還要 -(m/(pi*pj*pk))^n。

//如果有四個因子相乘的倍數pi*pj*pk*pl,
//先被減了4次,又被兩兩組合加了4*(4-1)/2=6次,
//還被三三組合減了4次,那麼還要再加一次 +(m/(pi*pj*pk*pl))^n。

//如果有五個因子相乘的倍數pi*pj*pk*pl*pt,
//先被減了5次,又被兩兩組合加了5*(5-1)/2=10次,
//被三三組合減了10次,被四四組合加了5次,
//還要減一次 -(m/(pi*pj*pk*pl*pt))^n。

//然後就發現了規律...質因子數相乘<10^15,應該不會超過20個吧...

void reads(ll &x){ //讀入優化(正負整數)
    ll fx=1;x=0;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')fx=-1;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    x*=fx; //正負號
}

const ll mod=1000000007;

ll primes[50019],cnt=0,n,m,ans; //質因子

void get_prime(ll x){ //找到x的所有質因子
    for(int i=2;i<=sqrt(x+1);i++){
        if(x%i!=0) continue;
        primes[++cnt]=i; //記錄質因子
        while(x%i==0) x/=i; //除掉所有i
    } if(x!=1) primes[++cnt]=x;
}

ll power(ll a,ll b){ //ksm
    ll anss=1; a=a%mod;
    while(b>0){
        if(b&1) anss=(anss*a)%mod;
        a=a*a%mod; b>>=1;
    } return anss;
}

void dfs(ll flag,ll now_cnt,ll now_sum){
    if(now_cnt==cnt+1){ //遞迴的最底層
        if(flag&1) ans=(ans-power(m/now_sum,n)+mod)%mod;
        else ans=(ans+power(m/now_sum,n))%mod;
        return; //判斷2^cnt種選擇方案之一的情況、加或減的對答案的影響
    } dfs(flag^1,now_cnt+1,now_sum*primes[now_cnt]); 
    dfs(flag,now_cnt+1,now_sum); //每個因子可以選擇乘上或者不乘
}

int main(){
    freopen("heal.in","r",stdin);
    freopen("heal.out","w",stdout);
    reads(n),reads(m),get_prime(m);
    dfs(0,1,1); //flag,當前列舉到的因子數,當前湊成的因子積 
    //flag中的0表示此層為奇數層,需要減,1表示此層為偶數層,需要加
    cout<<ans<<endl; return 0;
}

好了題目都分析完了...再次懷念一下AK的故事qwq

                                   ——時間劃過風的軌跡,那個少年,還在等你。