ICPC 2011

随便写个标题吧。。算不算标题党? 整理一下最近写的题目。

大连网络赛To Miss Our Children Time 背包问题,排个序就行了,题目描述不清。。

Find Metal Mineral 树形动归,f[x][j]表示以x为根的树,前i个子树放j个机器人不回来的最小值,DFS的感觉。f[x][0]表示放一个再出来。做的第一个树形动归,参照别人的代码,很巧妙的写法嘛。刚才看题目忘了具体怎么写了= =


void work(int x,int prev)
{
    for (int i=head[x];i!=-1;i=edge[i].next)
    {
        if (edge[i].y==prev) continue;
        work(edge[i].y,x);
        for (int j=k;j>=0;j--)
        {
            f[x][j]+=f[edge[i].y][0]+edge[i].w*2;
            for (int l=0;l<j;l++)
            f[x][j]=min(f[x][j],f[x][l]+edge[i].w*(j-l)+f[edge[i].y][j-l]);
        }
    }
}

PS:原来这个叫做分组背包= =

The Frog’s Games 比赛的时候以为是DP,结果就是个二分…

The kth great number 最简单的办法就是弄一个最小堆,堆顶就是答案,priority_queue用起来很爽。


priority_queue <int, vector, greater > heap;

if (heap.size()<k) heap.push(temp);
else if (temp>heap.top())
    {
        heap.pop();
        heap.push(temp);
    }

还可以写个treap..treap的删除还不会写= =

Dave 注意正方形的顶点不一定是题中的点。 把点分别按x和y排序,四条线扫描,写得比较乱= =

The 36th ACM/ICPC Asia Regional Shanghai Site —— Warmup Working in Beijing Parsing URL 两道水题,第一题题目说明不清楚= = 做做调节心情

上海网络赛 24 Puzzle 如果空位在角上则挪到中间的正方形里,然后比较8个角是否相同,相同才有可能有解。对于4*4,左右交换不改变逆序对,上下交换时逆序数的奇偶性改变一次(0-3,3-0,1-2,2-1)。 http://zhyu.me/acm/hdu-4021.html 觉得这个证明不完备,没想好怎么证。

Bombing multiset真的很爽…


typedef map<int, multiset > dict;

void work(dict &a;, dict &b;, int &x;)  //delete a(x) from b
{
    printf("%d\n",a[x].size());
    for (multiset::iterator iter=a[x].begin();iter!=a[x].end();iter++)
    {
        b[*iter].erase(x);
    }
    a[x].clear();
}

int main()
{
    int n,m,x,y;
    while (scanf("%d%d",&n;,&m;)!=EOF)
    {
        if (n==0 && m==0) break;
        dict a,b;
        for (int i=0;i<n;i++)
        {
            scanf("%d%d",&x;,&y;);
            a[x].insert(y);
            b[y].insert(x);
        }
        for (int i=0;i<m;i++)
        {
            scanf("%d%d",&x;,&y;);
            if (x==0) work(a,b,y);
            else work(b,a,y);
        }
        printf("\n");
    }
    return 0;
}

Game 比较简单的博弈问题,比赛的时候没静下心来想。 分组讨论,注意一个细节,9、10如果竖着的放好了,对方就不用抢这种了。

成都网络赛 Graph 给最短边求原图,原来可以这样写


void work(const int n)
{
    for (int k=0;k<n;k++)
    for (int i=0;i<n;i++)
    for (int j=0;j<n;j++)
    {
        if (i==j || i==k || k==j) continue;
        if ((!visited[i][j]) && map[i][k]+map[k][j]==map[i][j])
        {
            ++c;
            visited[i][j]=true;
        }
    }
}


printf("%d\n",n*(n-1)-c);

Rolling Hongshu 物理题,考虑顶点和所有bitter potato。题目描述挺好玩…

The Social Network 第一次用map。


map<string,int> num;

读入:


cin>>s1>>s2;
if (num.count(s1)) n1=num.find(s1)->second;
else
    {
        num.insert(make_pair(s1, ++count));
        n1=count;
        sn[n1]=s1;
    }
if (num.count(s2)) n2=num.find(s2)->second;
else
    {
        num.insert(make_pair(s2, ++count));
        n2=count;
        sn[n2]=s2;
    }
f[n1][++f[n1][0]]=n2;//f[n1]存n1的朋友们
f[n2][++f[n2][0]]=n1;

接下来就慢慢弄吧…

北京网络赛 Eliminate Witches! 模拟,递归处理,WA好几次= = 不过这个是我在今年网络赛时作出的第一道题= =

Panda 树状数组。a[i]表示以i开头的是不是wbw。自己没想到这种方法。


if (s[i]=='w' && s[i+1]=='b' && s[i+2]=='w') add(i,1);

Tourism Planning 第一个状态压缩DP,把某人去不去用二进制表示。 f[15][1030];//f[i][j]前i个景点,第j个状态的最大值 预处理当前状态能由哪些状态得到,如果不预处理HDU可以很快AC,BOJ会TLE= =

wolf5x 概率DP。 比赛时就想对了方法,读题不认真,以为第一步左右概率相同呢。 赛后写好,发现还是看错题了,以为是求停止位置,原来是求步数的期望,可以直接把所有状态的概率加起来!


int main()
{
    int t;
    int n,a,b;
    int i,j;
    double ans;
    double p[2010][4];
    double f[2010][4];
    double temp1,temp2,temp3;
    scanf("%d",&t;);
    while (t--)
    {
        scanf("%d%d%d",&n;,&a;,&b;);
        ans=0;
        for (i=1;i<=n;i++) scanf("%lf%lf%lf%lf",&p;[i][0],&p;[i][1],&p;[i][2],&p;[i][3]);
        memset(f,0,sizeof(f));
        temp1=1;
        for (i=a;i<=b;i++)
        {
            if (i>n)
            {
                ans+=temp1;
                break;
            }
            for (j=1;j<=3;j++) f[i][j]=temp1*p[i][j];
            temp1*=p[i][0];
        }
        for (i=a;i<=n;i++)
        {
            temp1=temp2=temp3=1;
            for (j=i+a;j<=i+b;j++)
            {
                if (j>n)
                {
                    ans+=f[i][1]*temp1+f[i][2]*temp2+f[i][3]*temp3;
                    break;
                }
                else
                {
                    f[j][1]+=(f[i][2]*temp2+f[i][3]*temp3)*p[j][1]; //表示以这种状态踩在j
                    f[j][2]+=(f[i][1]*temp1+f[i][3]*temp3)*p[j][2];
                    f[j][3]+=(f[i][1]*temp1+f[i][2]*temp2+f[i][3]*temp3)*p[j][3];
                    temp1*=p[j][0]+p[j][1];  //tempi表示f[prev][i]不能走的概率
                    temp2*=p[j][0]+p[j][2];
                    temp3*=p[j][0];
                }
            }
            ans+=f[i][1]+f[i][2]+f[i][3];
        }
        printf("%.8lf\n",ans);
    }
    return 0;
}

大连现场赛 The Last Puzzle 对于任意一段,都是从任意一端开始到中间,因为如果从中间开始,还是要先到两端再到最终节点。想通了这个就很好写了。 f[i][j][k]表示从i到j这一段,k表示从左或从右开始,所需的最短时间。不可能则记为-1。


/*
    f[i][j][1] 表示先按右端点的所需时间
    f[i][j][0] 表示先按左端点的所需时间
    r[i][j][0] (i,j)区间先左端点的话,(i+1,j)选哪个端点
    r[i][j][1] (i,j)区间先右端点的话,(i,j-1)选哪个端点
*/
int t[210],d[210],f[210][210][2];
int r[210][210][2];

void print(int a, int b, int c)
{
    if (b-a==1)
    {
        if (c) printf("%d %d\n",b,a);
        else printf("%d %d\n",a,b);
        return;
    }
    if (c)
    {
        printf("%d ",b);
        print(a,b-1,r[a][b][c]);
    }
    else
    {
        printf("%d ",a);
        print(a+1,b,r[a][b][c]);
    }
}
int main()
{
    freopen("zoj3541.txt","r",stdin);
    int n,i,j,k;
    while (scanf("%d",&n;)!=EOF)
    {
        memset(f,-1,sizeof(f));
        for (i=1;i<=n;i++) scanf("%d",&t;[i]);
        for (i=1;i<=n;i++) scanf("%d",&d;[i]);

        // 相邻的
        for (i=1;i<n;i++)
        {
            f[i][i+1][1]=f[i][i+1][0]=d[i+1]-d[i];
            if (f[i][i+1][1]>=t[i+1]) f[i][i+1][1]=-1;
            if (f[i][i+1][0]>=t[i]) f[i][i+1][0]=-1;
        }

        for (k=2;k<n;k++)
        {
            for (i=1;i<=n-k;i++)
            {
                j=i+k;

                // f[i][j][0]
                if (f[i+1][j][0]!=-1)
                {
                    f[i][j][0]=f[i+1][j][0]+d[i+1]-d[i];
                    r[i][j][0]=0;
                }
                if (f[i+1][j][1]!=-1)
                    if (f[i][j][0]!=-1)
                    {
                        if (f[i][j][0]>f[i+1][j][1]+d[j]-d[i])
                        {
                            f[i][j][0]=f[i+1][j][1]+d[j]-d[i];
                            r[i][j][0]=1;
                        }
                    }
                    else
                    {
                        f[i][j][0]=f[i+1][j][1]+d[j]-d[i];
                        r[i][j][0]=1;
                    }

                if (f[i][j-1][0]!=-1)
                {
                    f[i][j][1]=f[i][j-1][0]+d[j]-d[i];
                    r[i][j][1]=0;
                }
                if (f[i][j-1][1]!=-1)
                    if (f[i][j][1]!=-1)
                    {
                        if (f[i][j][1]>f[i][j-1][1]+d[j]-d[j-1])
                        {
                            f[i][j][1]=f[i][j-1][1]+d[j]-d[j-1];
                            r[i][j][1]=1;
                        }
                    }
                    else
                    {
                        f[i][j][1]=f[i][j-1][1]+d[j]-d[j-1];
                        r[i][j][1]=1;
                    }

                if (f[i][j][0]>=t[i]) f[i][j][0]=-1;
                if (f[i][j][1]>=t[j]) f[i][j][1]=-1;
            }
        }
        if (f[1][n][0]==-1 && f[1][n][1]==-1) puts("Mission Impossible");
        else
            if (f[1][n][0]!=-1) print(1,n,0);
            else print(1,n,1);
    }
    return 0;
}


Hexadecimal View 水题,不知道可以用 %x 输出…

Number String f[i][j]存当前所有可能情况,即i=n时只有f[n][1]。表示字符串中第i位是,表中第j个有几种情况。f[i+1]保存的数量比f[i]少一个,因为有一个数字被选走了。


for (i=1;i<=n;i++) f[1][i]=1;
for (int ii=0;ii<n;ii++)
{
    i=ii+2;
    if (str[ii]=='I')
    {
        f[i][1]=f[i-1][1];
        for (j=2;j<=n-i+1;j++) f[i][j]=(f[i-1][j]+f[i][j-1])%MOD;
    }
    else if (str[ii]=='D')
    {
        f[i][n-i+1]=f[i-1][n-i+2];
        for (j=n-i;j>=1;j--) f[i][j]=(f[i-1][j+1]+f[i][j+1])%MOD;
    }
    else
    {
        sum=0;
        for (j=1;j<=n-i+2;j++) sum=(sum+f[i-1][j])%MOD;
        for (j=1;j<=n-i+1;j++) f[i][j]=sum;
    }
}
printf("%d\n",f[n][1]);

福州网络赛 SanguoSHA 当时不爽,写这题写了好久= = 最后写好了觉得会WA,于是没交,回宿舍交了发现过了。 STL里居然有全排列… next_permutationprev_permutation

=== 仔细想想有些题还是可以做的,并不是不会算法,而是想不到。另外数学太烂了。

大二,作业没大一多了,更加觉得时间不够用。平时训练做题效率很低。还有好多想学的东西呢。


comments powered by Disqus