10.7 考试

T1

对于每一个G,最小耗时是她前面B的个数,但是当G连在一起时,就有可能把她卡住

 

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <cmath>
#include <vector>
#include <algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
using namespace std;
const int N=1000006;

char s[N];
int n;

int main(){

    scanf("%s",s);
    n=strlen(s);
    int ans=0,con=0;
    for(int i=0;i<n;++i)
    {
        if(s[i]=='B')
            ++con;
        else
            ans=max(ans+1,con);
    }
    cout<<ans;
}
T1

 

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <ctime>
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
using namespace std;
const int N=1000006;

char s[N];
int n;
int pre[N],nxt[N];
//bool flag[N];

int work()
{
    int now=1;
    while(now<=n&&s[now]!='G')++now;
    if(s[now]=='B')
    {
        nxt[0]=n+1;
        pre[n+1]=0;
    }
    else
    {
        nxt[0]=now;
        pre[now]=0;
        for(int i=now;i<=n;)
        {
            now=i;
            while(now<=n&&s[now]=='G')++now;
            while(now<=n&&s[now]=='B')++now;
            pre[now]=i;
            nxt[i]=now;
            i=now;
        }
    }

    /*for(int i=nxt[0];i<=n;i=nxt[i])
        printf("i=%d\n",i);*/

    //for(int i=0;i<=n+1;++i)
    //    printf("i=%d %d %d\n",i,pre[i],nxt[i]);

    int t=0,swif;
    while(1)
    {
        ++t;
        swif=0;
        for(int i=nxt[0];i<=n;i=nxt[i])
        {
            //printf("i=%d\n",i);
            //system("pause");
            if(i==1)
                continue;
            swif=1;

            nxt[pre[i]]=i-1;
            pre[nxt[i]]=i-1;
            pre[i-1]=pre[i];
            nxt[i-1]=nxt[i];
            s[i]='B';
            s[i-1]='G';
            
            if(i-2<1||s[i-2]=='B')
            {
                if(i+1<=n&&s[i+1]=='G')
                {
                    pre[nxt[i]]=i+1;
                    nxt[i-1]=i+1;
                    pre[i+1]=i-1;
                    nxt[i+1]=nxt[i];
                }
            }
            else
            {
                pre[nxt[i]]=pre[i];
                nxt[pre[i]]=nxt[i];
                if(i+1<=n&&s[i+1]=='G')
                {
                    pre[nxt[i]]=i+1;
                    nxt[pre[i]]=i+1;
                    pre[i+1]=pre[i];
                    nxt[i+1]=nxt[i];
                }
            }
        }

        if(!swif)
            return t-1;

        //for(int i=0;i<=n+1;++i)
        //    printf("i=%d %d %d\n",i,pre[i],nxt[i]);

        /*for(int i=1;i<=n;++i)
            printf("%c",s[i]);
        printf("\n");*/

    }
}

int main(){

    //freopen("T1.in","r",stdin);
    //freopen("T111.out","w",stdout);

    //freopen("line.in","r",stdin);
    //freopen("line.out","w",stdout);

    scanf("%s",s);
    n=strlen(s);
    for(int i=n;i>=1;--i)
        s[i]=s[i-1];
    s[0]=0;
    cout<<work();
    //printf("\n%d\n",clock());
}
        /*nxt[0]=now;
        pre[now]=0;
        for(int i=now;i<=n;)
        {
            now=i;
            while(s[now]=='G'&&now<=n)++now;--now;
            if(s[now]=='B')
            {
                nxt[i]=n+1;
                pre[n+1]=i;
            }
            else
                if(now!=i)
                {
                    pre[now]=i;
                    nxt[i]=now;
                }
            i=now;
            ++now;
            while(now<=n&&s[now]=='B')++now;
            pre[now]=i;
            nxt[i]=now;
            i=now;
        }*/
"超快的"链表模拟

 

T2

60分dp:

f[i][j][k] 前i位,最长长度==j,最后一个字符是k

$$f[i][j][k]=\sum_{l=i-j}^{i-1}\sum_{p!=k}^mdp[l][j][p]*sum[l+1][j][k]+\sum_{h=1}^{j-1}\sum_{p!=k}dp[i-j][h][p]*sum[i-j+1][i][k]$$

其中sum是从i到j字符全是k的概率,$O(n^2m)$求出

正解有两个,一个是$O(n^2m^2)$的,一个是$O(n^2m)$的

后一个更好理解,也更快

dp[i][j][k] 到了第i个位置,最长长度<=j,最后一个字符是k 的概率

f[i][j] 到了第i个位置,最长长度<=j 的概率 (其实就是把dp的第三维去掉了)

$$dp[i][j][k]=f[i-1][j]*sum[i][i][k]-(f[i-j-1][j]-dp[i-j-1][j][k])*sum[i-j][i][k]$$

其实就是把所有情况都先转移过来,然后去掉不合法的情况

 

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <iostream>
#define dd double
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;

int n,m;
dd p[1006][16];
dd s[1006][1006][16];
dd f[1006][1006],dp[1006][1006][16];

void chu()
{
    for(int i=1;i<=m;++i)
        p[0][i]=1.0;

    for(int k=1;k<=m;++k)
        for(int i=1;i<=n;++i)
        {
            s[i][i][k]=p[i][k];
            for(int j=i+1;j<=n;++j)
                s[i][j][k]=s[i][j-1][k]*p[j][k];
        }
}

dd work()
{
    dd ans=0;
    for(int i=0;i<=n;++i)
        f[0][i]=1;
    for(int i=1;i<=n;++i)
        for(int j=1;j<=n;++j)
            for(int k=1;k<=m;++k)
            {
                //printf("i=%d j=%d k=%d\n",i,j,k);
                dp[i][j][k]=f[i-1][j]*s[i][i][k];
                if(i-j-1>=0)
                    dp[i][j][k]-=(f[i-j-1][j]-dp[i-j-1][j][k])*s[i-j][i][k];
                f[i][j]+=dp[i][j][k];
            }
    for(int j=1;j<=n;++j)
        ans+=(f[n][j]-f[n][j-1])*j;
    return ans;
}

int main(){

    //freopen("1.in","r",stdin);

    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
            scanf("%lf",&p[i][j]);
    chu();
    printf("%.5lf",work());
}
T2

 

T3

设B=sqrt(n)

把集合大小>B的定为重集合,<=B的定为轻集合

处理一个数组cnt[][]记录每一个集合与重集合的交集个数,这个可以$O(n\sqrt{n})$处理

每一个重集合维护 sum、add,分别表示重集合不加标记的值和标记的值

然后插入、询问分4个操作:

1.轻集合add,暴力加轻集合内的元素,再更新与之有交集的重集合的sum

2.重集合add,直接标记

3.轻集合qq,直接暴力统计+与之有交集的重集合标记*cnt[i][j]

4.重集合qq,sum+与之有交集的重集合标记*cnt[i][j]

 

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <cmath>
#include <vector>
#include <algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
using namespace std;
const int N=100006;

int n,m,Q;
int B;
ll a[N];

vector<int> ji[N],dian[N];
int num[N];

int zhong[N],con,dui[N];
int cnt[N][336];

ll biao[N],sum[N];

void chu()
{
    int temp,s1,s2;
    for(int i=1;i<=m;++i)
    {
        for(int j=0;j<num[i];++j)
        {
            s1=dian[ji[i][j]].size();
            for(int k=0;k<s1;++k)
                ++cnt[i][ dian[ji[i][j]][k] ];
        }
    }
}

ll qq(int x)
{
    ll ans=0;
    if(num[x]>B)
    {
        ans+=sum[dui[x]];
        for(int i=1;i<=con;++i)
            ans+=cnt[x][i]*biao[i];
        return ans;
    }
    for(int i=0;i<num[x];++i)
        ans+=a[ji[x][i]];
    for(int i=1;i<=con;++i)
        ans+=cnt[x][i]*biao[i];
    return ans;
}

void add(int x,int val)
{
    if(num[x]>B)
    {
        biao[dui[x]]+=val;
        return ;
    }
    for(int i=0;i<num[x];++i)
        a[ji[x][i]]+=val;
    for(int i=1;i<=con;++i)
        sum[i]+=cnt[x][i]*val;
}

int main(){

    scanf("%d%d%d",&n,&m,&Q);
    B=sqrt(n);
    for(int i=1;i<=n;++i)
        scanf("%lld",&a[i]);
    int tin1,tin2;
    for(int i=1;i<=m;++i)
    {
        scanf("%d",&num[i]);
        if(num[i]>B)
        {
            zhong[++con]=i;
            dui[i]=con;
        }
        for(int j=1;j<=num[i];++j)
        {
            scanf("%d",&tin1);
            ji[i].push_back(tin1);
            if(zhong[con]==i)
            {
                dian[tin1].push_back(con);
                sum[con]+=a[tin1];
            }
        }
    }
    chu();
    int op;
    for(int i=1;i<=Q;++i)
    {
        scanf("%d",&op);
        if(op==1)
        {
            scanf("%d",&tin1);
            printf("%lld\n",qq(tin1));
        }
        else
        {
            scanf("%d%d",&tin1,&tin2);
            add(tin1,tin2);
        }
    }
}
T3

 

 

总结:

第一题是思考题,但是我一意孤行的认为跟 clock 那个题一样 打了链表...

对于2.3题,当然要打暴力了....

但是最近总是想不出来...

 

posted @ 2017-10-08 06:31  A_LEAF  阅读(149)  评论(0编辑  收藏  举报