codeforces 187 (div2)題解

來源:互聯網
上載者:User


http://codeforces.com/problemset/problem/315/A


這兩天做了兩場CF的題(div2),沒事補個題解吧。

A題:題目很水,但是有些噁心的trick,比如有的罐子可以開啟沒有出現的編號的罐子,還有自己不能開啟自己,題目沒看清,WA了一堆,最後直接O(n^2)暴力水過。。。

#include <iostream>#include <stdio.h>#include <algorithm>#include <string.h>#define maxn 100010using namespace std;int a[110],b[110],num[110];int main(){    //freopen("dd.txt","r",stdin);    int n,i;    scanf("%d",&n);    int sum=0;    for(i=0;i<n;i++)    {        scanf("%d%d",&a[i],&b[i]);    }    for(i=0;i<n;i++)    {        for(int j=0;j<n;j++)        {            if(i!=j)            {                if(b[i]==a[j])                {                    num[j]=1;                }            }        }    }    for(i=0;i<n;i++)    sum+=num[i];    printf("%d\n",n-sum);    return 0;}


http://codeforces.com/problemset/problem/315/B

B題:初看題意以為要用線段樹之類的資料結構解決,其實不用,因為操作2是對所有元素的操作,我們只需要維護一個值sum記錄到目前為止操作2的累加和即可,同時在做操作1時,假如要把一個數賦值為x,我們只要將它調整為賦值x-sum即可,對於操作三的詢問,輸出a[qi]+sum即為所求。


#include <iostream>#include <string.h>#include <algorithm>#include <stdio.h>#define maxn 100010#define ll long longusing namespace std;ll a[maxn];int main(){    //freopen("dd.txt","r",stdin);    int n,i,m;    ll sum=0;    scanf("%d%d",&n,&m);    for(i=1;i<=n;i++)    scanf("%I64d",&a[i]);    while(m--)    {        int t,x,y;        scanf("%d",&t);        {            if(t==1)            {                scanf("%d%d",&x,&y);                a[x]=y-sum;            }            else if(t==2)            {                scanf("%d",&x);                sum+=x;            }            else            {                scanf("%d",&x);                printf("%I64d\n",sum+a[x]);            }        }    }    return 0;}


http://codeforces.com/problemset/problem/315/C
C題:題目有些長,但是看了範例還是很容易明白的,因為di的計算方法只和i前面的人還有人的總數n有關,且我們去掉人的順序也是從小到大,所以我們可以從左往右一個一個判定a[i]是否應該被去掉,在判斷的同時我們維護兩個值,po表示當前待判斷的人前面有多少人(沒有被去掉),nn表示當前還剩多少人。那麼對於每一個人計算di,若需要被去掉,則nn--,否則po++,如何快速計算di還是比較好想的,可以用類似dp的方法解決,具體實現請參考代碼。



#include <iostream>#include <string.h>#include <stdio.h>#include <algorithm>#include <assert.h>#define maxn 200010#define ll long longusing namespace std;ll a[maxn];int vis[maxn];int main(){   //freopen("dd.txt","r",stdin);   int n,k;   scanf("%d%d",&n,&k);   int i,nn=n,po=1;//nn表示還剩幾人,po表示當前確定留下的人的數量   ll tmp=0,d=0;   scanf("%I64d",&a[1]);   for(i=2;i<=n;i++)   {       scanf("%I64d",&a[i]);       d=tmp-po*a[i]*(nn-po-1);//計算di       if(d<k)//說明去掉一個       {           vis[i]=1;           nn--;       }       else       {           tmp+=po*a[i];           po++;       }   }   for(i=1;i<=n;i++)   if(vis[i])   printf("%d\n",i);    return 0;}


http://codeforces.com/problemset/problem/315/D

D題:首先很容易知道,若 [a, b] 串最多能obtain(具體含義見題目描述)x個 [c, d]串,則答案就為x。進一步,設[a,b]最多能obtain
y個c串,則x=y/d。·求y的過程類似於求迴圈節,設num[i]表示[a,i]能obtain多少個c串,且設l2[i]表示[a,i]匹配完後最後一個匹配到c串的第幾個字元,然後求迴圈節即可,具體實現還需要些細節,不嫌代碼醜的話可以參考代碼:


#include <iostream>#include <string.h>#include <algorithm>#include <stdio.h>#define maxn 100010using namespace std;char s1[110],s2[110];int num[10100],vis[110];int main(){    //freopen("dd.txt","r",stdin);    int b,d;    scanf("%d%d",&b,&d);    scanf("%s%s",s1,s2);    int len1=strlen(s1),len2=strlen(s2);    int t=0,l1=0,l2=0,sum=0,old=0;    num[0]=0;    int v[26];    memset(v,0,sizeof(v));    for(int i=0;i<len1;i++)    v[s1[i]-'a']++;    for(int i=0;i<len2;i++)    {        if(!v[s2[i]-'a'])        {            printf("0\n");            return 0;        }    }    memset(vis,-1,sizeof(vis));    vis[0]=0;    while(1)    {        if(s1[l1]==s2[l2])        {            l1++;            l2++;        }        else        l1++;        if(l2==len2)        {            sum++;            l2=0;        }        if(l1>len1)        {            t++;            num[t]=sum;            l1=0;            if(vis[l2]!=-1)            {                old=vis[l2];                break;            }            vis[l2]=t;        }    }    int tmp=0;    if(b<=t)    {        tmp=num[b];    }    else    {        tmp=num[t]+(num[t]-num[old])*((b-t)/(t-old));        b-=t;        b%=(t-old);        tmp+=num[old+b]-num[old];    }    printf("%d\n",tmp/d);    return 0;}


http://codeforces.com/problemset/problem/315/E
E題:很水的dp,易知我們要求的就是a串的所有不同的非下降子序列中,各位元乘積的和,我們設dp[i]表示以i結尾的非下降子序列的答案,我們從左至右一步一步更新dp值,轉移方程很簡單,為: dp[i]=(dp[1]+dp[2]+……dp[i])*i+i,簡單點表述就是我在之前求得的以x(x<=i)結尾的非下降子序列後加上一個i,然後再加上i自身,這樣可以保證序列不重複,至於為什麼在紙上畫畫就知道了,直接這麼做是不行的,顯然會逾時,區間和還有單點更新可以用線段樹或者樹狀數組維護,以下是樹狀數組的實現。


#include <iostream>#include <stdio.h>#include <string.h>#define ll long long#define maxn 1000010#define mod 1000000007using namespace std;ll dp[maxn],c[maxn];int nn=1000000;int lowbit(int x){    return x&(-x);}void add(int x,ll val){    while(x<=nn)    {        c[x]=(c[x]+val)%mod;        x+=lowbit(x);    }}ll getsum(int x){    ll sum=0;    while(x>0)    {        sum=(c[x]+sum)%mod;        x-=lowbit(x);    }    return sum;}int main(){    //freopen("dd.txt","r",stdin);    int i,n,x;    scanf("%d",&n);    for(i=1;i<=n;i++)    {        scanf("%d",&x);        ll tmp=dp[x];        dp[x]=(getsum(x)*x+x)%mod;        add(x,((dp[x]-tmp)%mod+mod)%mod);    }    ll ans=0;    for(i=1;i<=1000000;i++)    {        ans+=dp[i];    }    ans%=mod;    cout<<ans<<endl;    return 0;}


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.