zoukankan      html  css  js  c++  java
  • Topcoder SRM 607 div1题解

    好久没来写了,继续继续。。。

    Easy(250pts):

    //前方请注意,样例中带有zyz,高能预警。。。

    题目大意:给你一个字符串,中间有一些是未知字符,请你求出这个字符串的回文子串个数的期望值。数据满足字符最多2500个。

    我们考虑每一个子串,它对答案的贡献度就是它是回文串的概率,那么我们扫一遍就可以了,

    这样做时间复杂度O(n^3),显然过不去。

    我们考虑一下对于一个子串,在判断其是回文串的时候,我们一定是从中间往两边扫的,那么其实中间这些子串我们已经统计过答案了,

    也就是说,我们通过枚举中间点来统计答案就可以了,

    时间复杂度O(n^2),代码如下:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 string s;
     4 double ans=0.0;
     5 int n;
     6 class PalindromicSubstringsDiv1
     7 {
     8     public:
     9     double expectedPalindromes(vector <string> S1, vector <string> S2)
    10     {
    11         for (int i=0;i<S1.size();i++) s+=S1[i];
    12         for (int i=0;i<S2.size();i++) s+=S2[i];
    13         n=s.length();
    14         for (int i=0;i<n;i++)
    15         {
    16 //i means the middle point of the substring
    17             double now=1.0;
    18             int lx=i-1,rx=i+1;
    19             while (lx>=0&&rx<n)
    20             {
    21                 if (s[lx]=='?'&&s[rx]=='?') now=now*1.0/26.0;
    22                 else if (s[lx]!='?'&&s[rx]!='?'&&s[lx]==s[rx]) now=now*1.0;
    23                 else if (s[lx]!='?'&&s[rx]!='?') now=0.0;
    24                 else now=now*1.0/26.0;
    25                 ans+=now;
    26                 --lx;++rx;
    27             }
    28             now=1.0,lx=i,rx=i+1;
    29             while (lx>=0&&rx<n)
    30             {
    31                 if (s[lx]=='?'&&s[rx]=='?') now=now*1.0/26.0;
    32                 else if (s[lx]!='?'&&s[rx]!='?'&&s[lx]==s[rx]) now=now*1.0;
    33                 else if (s[lx]!='?'&&s[rx]!='?') now=0.0;
    34                 else now=now*1.0/26.0;
    35                 ans+=now;
    36                 --lx,++rx;
    37             }
    38         }
    39         ans+=1.0*n;
    40         return ans;
    41     }
    42 };

    Medium(475pts):

    题目大意:有一串数字(0~9)围成了一个环,每一次可以选取一段区间,然后同时+1或者-1,(0 -1变成了9,9 +1变成了0)求现在到目标的最少操作次数。数据满足最多2500个元素。

    这题怎么就475分了啊。。。感觉这么难。。。

    容易观察到,结果只在%10意义下有用,所以先处理出差%10的余数。

    接下来需要一个观察:如果两个区间一个是+操作,一个是-操作,那么一定可以做到这两个区间不相交。

    然后考虑dp,f[i][j][k]表示当前在第i位,区间已经改变了j,而k则代表是+操作还是-操作。

    这样时间复杂度是O(n^3)的,可以通过div2那个题。

    然后我就跑去看官方题解了,然后没看懂。。。

    大概的感受就是,观察出其实一个区间的操作改变不会很多,就只有-10~10以内,然后判一下就好了。

    时间复杂度O(n^2),带一个常数,代码如下:

     1 #include <bits/stdc++.h>
     2 #define Maxn 2507
     3 #define Maxm 5507
     4 #define inf 200000007
     5 using namespace std;
     6 string S,T;
     7 int n;
     8 int d[Maxn];
     9 int f[Maxn][Maxm][2];
    10 bool vis[Maxn][Maxm][2];
    11 class CombinationLockDiv1
    12 {
    13     int tryit(int pos, int x, int dir)
    14     {
    15 //pos means which number it is dealing with now
    16 //x means the addition of the interval
    17 //dir means the interval is to add or to minus
    18         if (vis[pos][x][dir]) return f[pos][x][dir];
    19         vis[pos][x][dir]=true;
    20         if (pos==n)
    21         {
    22             f[pos][x][dir]=0;
    23             return f[pos][x][dir];
    24         }
    25         f[pos][x][dir]=inf;
    26         for (int newdir=0;newdir<=1;newdir++)
    27         {
    28             for (int y=max(x-9,0);y<=min(x+9,5500);y++)
    29             {
    30                 if (newdir==0&&((d[pos]-y%10+10)%10!=0)) continue;
    31                 if (newdir==1&&((d[pos]+y)%10!=0)) continue;
    32                 int z;
    33                 if (newdir!=dir) z=y; else z=max(y-x,0);
    34                 f[pos][x][dir]=min(f[pos][x][dir],z+tryit(pos+1,y,newdir));
    35             }
    36         }
    37         return f[pos][x][dir];
    38     };
    39     public:
    40     int minimumMoves(vector <string> P, vector <string> Q)
    41     {
    42         for (int i=0;i<P.size();i++) S+=P[i];
    43         for (int i=0;i<Q.size();i++) T+=Q[i];
    44         n=S.size();
    45         for (int i=0;i<n;i++) d[i]=(S[i]-T[i]+10)%10;
    46         memset(vis,false,sizeof(vis));
    47         memset(f,0,sizeof(f));
    48         return tryit(0,0,0);
    49     }
    50 };

    Hard(1000pts):

    题目大意:有n个轮子,半径间隔完全相等地一横排排在一条直线上,有个起点和终点完全对称(到最近的轮子距离也相同,也在x轴上),现在有根绳子,可以任意地从S开始环绕轮子,然后到T。这样的绳子显然有无数多条,给定k,求第k短的长度。数据满足n<=50,k<=10^18。

    这题的第一步非常难,也非常关键。(然而cyand1317表示并不难。。。)

    所有的绳子都可以划分成四种的拼凑,第一种是从起点到上半部分,第二种是轮子的上半部分到下一个轮子的上半部分,第三种是轮子的上半部分到下一个轮子的下半部分,第四种是包围一个轮子半圈(轮子的上半部分到轮子的下半部分)。

    然后我们发现,第一种对于所有绳子都恰好有两段,于是我们只需要考虑后三段就可以了,表示成一个三元组(x,y,z)。

    我们先dp预处理出每一个状态的方案数,我们需要四维x,y,z以及一个数字表示方向。

    然而实际上不需要,第四种情况的奇偶性就可以判断方向,然后直接O(n^3)的dp就可以了,

    最后我们需要二分答案,然后来判定。

    需要注意的是,本题数据这么大,显然是存不下的,我们需要设定一个inf,当数大于inf的时候,直接不参与计算。

    时间复杂度O(n^3),代码如下:

     1 #include <bits/stdc++.h>
     2 #define inf (1LL<<60)
     3 using namespace std;
     4 double A,B,R;
     5 int n;
     6 long long combination[100007][47];
     7 long long f[77][77][67][2];
     8 class PulleyTautLine
     9 {
    10     long long calc(long long n, long long k)
    11     {
    12         k=min(k,n-k);
    13         if (k==0) return 1;
    14         if (k==1) return n;
    15         if (k==2&&0.5*n*(n-1)<1.1*inf) return 1LL*n*(n-1)/2;
    16         if (k==3&&1.0/6*n*(n-1)*(n-2)<1.1*inf) return 1LL*n*(n-1)*(n-2)/6;
    17         if (k<40&&n<100000) return combination[n][k];
    18         return inf;
    19     }
    20     long long tryit(double len)
    21     {
    22         long long res=0;
    23         for (int i=0;i<70;i++)
    24             for (int j=0;j<70;j++)
    25             {
    26 //number of moves A&B
    27 //number of moves R
    28                 if (f[i][j][n-1][0]>0)
    29                 {
    30                     for (int k=0;k<=i;k++)
    31                     {
    32 //number of moves A
    33                         double L=k*A+(i-k)*B+j*R;
    34                         if (L>len) continue;
    35 //max number of circles
    36                         long long cir=(long long)((len-L)/2.0/R);
    37                         long long cnt1=calc(i,k),cnt2=calc(cir+i+1,i+1);
    38                         if (cnt2>inf/cnt1/f[i][j][n-1][0]) return inf;
    39                         res+=1LL*cnt1*cnt2*f[i][j][n-1][0];
    40                         if (res>inf) return inf;
    41                     }
    42                 }
    43             }
    44         return res;
    45     }
    46     public:
    47     double getLength(int d, int r, int N, long long k)
    48     {
    49         n=N;
    50         A=d,B=sqrt((double)d*d-4.0*r*r)+2.0*r*asin(2.0*r/d),R=r*acos(-1.0);
    51         double L=sqrt((double)d*d-(double)r*r)+r*asin((double)r/d);
    52         if (n==1) return (k-1)/2*2.0*R+2.0*L;
    53         memset(combination,0,sizeof(combination));
    54         for (int i=0;i<=100000;i++)
    55         {
    56             combination[i][0]=1;
    57             for (int j=1;j<=40;j++)
    58                 combination[i][j]=min(inf,combination[i-1][j]+combination[i-1][j-1]);
    59         }
    60         memset(f,0,sizeof(f));
    61         f[0][0][0][0]=2;
    62         for (int i=0;i<70;i++)
    63             for (int j=0;j<70;j++)
    64                 for (int k=0;k<n;k++)
    65                     for (int p=0;p<=1;p++)
    66                     {
    67 //there are three kinds of moves
    68 //one is to change the direction
    69 //the other two are move forward (become nearer or farer)
    70                         if (p==0) f[i][j+1][k][1]=min(inf,f[i][j+1][k][1]+f[i][j][k][p]);
    71                         if (j%2==0&&k<n-1) f[i+1][j][k+1][0]=min(inf,f[i+1][j][k+1][0]+f[i][j][k][p]);
    72                         if (j%2==1&&k>0) f[i+1][j][k-1][0]=min(inf,f[i+1][j][k-1][0]+f[i][j][k][p]);
    73                     }
    74         double left=0.0,right=1000.0*A,mid;
    75         for (int i=1;i<=50;i++) 
    76         {
    77             mid=(double)(left+right)/2;
    78             if (tryit(mid)>=k) right=mid; else left=mid;
    79         }
    80         return mid+2.0*L;
    81     }
    82 };
  • 相关阅读:
    交易之道
    走出幻觉,走向成熟(阅读心得一)
    爱由心生
    正则资料整理(转载)
    需要学习的.NET技术(转载)
    抽象类与接口的区别
    心存感激
    MYSQL 远程访问被限制
    PHP积累
    Git积累
  • 原文地址:https://www.cnblogs.com/Tommyr7/p/6934876.html
Copyright © 2011-2022 走看看