UVA写题记录

UVA写题记录

UVA 1451

Description

求一个长度为N的01串长度至少为L的子串的数字平均值最大的起点和终点

Solution

可以看成斜率来做

但我写的二分,二分平均值然后扫一遍就行了

O(nlogn)

#include<bits/stdc++.h>

using namespace std;

inline int read()
{
    int f = 1,x = 0;
    char ch;
    do
    {
        ch = getchar();
        if(ch == '-') f = -1;
    }while(ch < '0'|| ch > '9');
    do
    {
        x = (x<<3) + (x<<1) + ch - '0';
        ch = getchar();
    }while(ch >= '0'&&ch <= '9');
    return f*x;
} 

#define eps 1e-6
const int MAXN = 100000 + 10;

int T,pos;
int ans1,ans2;
int n,L;
char a[MAXN];
double sum[MAXN];

inline bool check(double x)
{
    for(int i=1;i<=n;i++) sum[i] = sum[i-1] + a[i-1] - '0' - x;
    double minn = 0,maxx = -200000.0;
    for(int i=L;i<=n;i++)
    {
        if(minn >= sum[i-L]) minn = sum[i-L],pos=i-L+1;
        if(sum[i]-minn>maxx + eps)
        {
            maxx = sum[i] - minn;
            ans1 = pos;
            ans2 = i;
        }
    }
    if(maxx + eps > 0) return 1;
    return 0;
}

int main()
{
    T = read();
    while(T--)
    {
        n = read(),L = read();
        scanf("%s",a);
        double l = 0.0 ,r = 1.0;
        for(int i=1;i<=100;i++)
        {
            double mid = (r+l)/2.0;
            if(check(mid)) l = mid;
            else r = mid;
        }
    //    check(l+eps);
        printf("%d %d\n",ans1,ans2);
    }
}
View Code

 UVA 1437

Description

给定两个长度相等且只有小写字母组成的字符串S,T
每步把S的连续子串变成相同的字母
至少需要多少步可以让S变成T

Solution

普及组难度DP

考虑一个空串至少要刷几次能到B串

一个显然的区间DP

然后再考虑A串来刷

另  $ DP_i $  表示A串前I个字母需要刷多少次能和B匹配

显然如果相同位一样可以选择不刷

#include<bits/stdc++.h>

using namespace std;

inline int read()
{
    int f = 1,x = 0;
    char ch;
    do
    {
        ch = getchar();
        if(ch == '-') f = -1;
    }while(ch < '0'|| ch > '9');
    do
    {
        x = (x<<3) + (x<<1) + ch - '0';
        ch = getchar();
    }while(ch >= '0'&&ch <= '9');
    return f*x;
} 

const int MAXN = 200 + 10;

char a[MAXN],b[MAXN];
int f[MAXN][MAXN];
int dp[MAXN];

int main()
{
    while(~scanf("%s%s",a+1,b+1))
    {
        int len = strlen(a+1);
        memset(f,0,sizeof(f));
        for(int i=0;i<=len;i++) f[i][i] = 1;
        for(int l=2;l<=len;l++)
        {
            for(int i=1;i+l-1<=len;i++)
            {
                int j = i + l - 1;
                f[i][j] = min(f[i][j-1],f[i+1][j]) + !(b[i]==b[j]);
                for(int k=i+1;k<j;k++) f[i][j] = min(f[i][j],f[i][k]+f[k+1][j]);
            }
        }
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=len;i++) dp[i] = f[1][i];
        for(int i=1;i<=len;i++)
        {
            if(a[i]==b[i]) dp[i] = dp[i-1];
            else
            {
                for(int j=1;j<i;j++) dp[i] = min(dp[i],dp[j]+f[j+1][i]);
            }
        }
        printf("%d\n",dp[len]);
    }
}
View Code

UVA 11136

Description

提供一个支持插入,查询和删除最大值最小值的数据结构

Solution

直接mutiset

#include<bits/stdc++.h>

using namespace std;

inline int read()
{
    int f = 1,x = 0;
    char ch;
    do
    {
        ch = getchar();
        if(ch == '-') f = -1;
    }while(ch < '0'|| ch > '9');
    do
    {
        x = (x<<3) + (x<<1) + ch - '0';
        ch = getchar();
    }while(ch >= '0'&&ch <= '9');
    return f*x;
} 

int n;

int main()
{
    while(~scanf("%d",&n))
    {
        if(!n) return 0;
        long long ans = 0;
        multiset<int>s;
        for(int i=1;i<=n;i++)
        {
            int k = read();
            for(int i=1;i<=k;i++)
            {
                int a = read();
                s.insert(a);
            }    
            ans += *s.rbegin() - *s.begin();
            s.erase(s.begin());s.erase(s.find(*s.rbegin()));
        }
        printf("%lld\n",ans);
        
    }
}
View Code

 

UVA 1639

Description

有两个盒子各有n (n<=2e5) 个糖,每天随机选一个(概率分别为p,1-p),然后吃一颗糖。直到有一天,打开盒子一看,没糖了!输入n,p,求此时另一个盒子里糖的个数的数学期望。

Solution

假设没糖的是第一个盒子,那么第一个盒子拿了n+1次,第二个盒子拿了0次到n次,我们可以假设第二个盒子最终剩了i颗糖,这个时候概率显然就是

$ \binom{2n-i}{n} p^{n+1} \times  (1-p)^{n-i}  $

但这道题真正的考点其实是在精度上,可以看出这个式子算出来的值是很小的,无法保证精度

所以取个对数就可以了

#include<bits/stdc++.h>

using namespace std;

inline int read()
{
    int f = 1,x = 0;
    char ch;
    do
    {
        ch = getchar();
        if(ch == '-') f = -1;
    }while(ch < '0'|| ch > '9');
    do
    {
        x = (x<<3) + (x<<1) + ch - '0';
        ch = getchar();
    }while(ch >= '0'&&ch <= '9');
    return f*x;
} 

const int MAXN = 2e5 + 10;

long double L[(MAXN<<1)+5];
int n;
double p;
int C=0;

int main()
{
    for(int i=1;i<=(MAXN<<1);i++) L[i] = L[i-1] + log(i);
    while(~scanf("%d%lf",&n,&p))
    {
        double ans = 0.0;
        for(int i=1;i<=n;i++)
        {
            long double res1 = L[2*n-i]-L[n]-L[n-i];
            long double res2 = res1 + log(p)*(n+1) + log(1-p)*(n-i);
            long double res3 = res1 + log(1-p)*(n+1) + log(p)*(n-i);
            ans += i * (exp(res2)+exp(res3));  
        }
        printf("Case %d: %.6lf\n",++C,ans);
    }
}

 

UVA 11971

Description

在直线上随机取k个点,分成的k+1段拼起来能组成多边形的概率

Solutuon

能组成多边形的条件是最大边要小于其他边之和

于是可以知道最大边长度要小于n/2

就像CSPd2t1一样从反面考虑,当不能组成多边形时大于n/2的边只能有一条

我们先假设最长边以左边为起点,于是剩下的点都只能在中点往右才不能组成多边形,此时概率为 $ \frac{1}{2^{k}} $

且对于每种情况,最长边可以向右平移,一共有k+1种放法

所以答案就是 $ 1-(k+1) \times \frac{1}{2^{k}}  $

#include<bits/stdc++.h>

using namespace std;

#define LL long long

inline LL read()
{
    LL f = 1,x = 0;
    char ch;
    do
    {
        ch = getchar();
        if(ch == '-') f = -1;
    }while(ch < '0'|| ch > '9');
    do
    {
        x = (x<<3) + (x<<1) + ch - '0';
        ch = getchar();
    }while(ch >= '0'&&ch <= '9');
    return f*x;
} 

inline LL Pow(LL a, LL b)
{
    LL ans = 1,mul = a;
    while(b)
    {
        if(b&1) ans = ans * mul;
        mul = mul * mul;
        b>>=1;
    }
    return ans;
}

inline LL gcd(LL a ,LL b)
{
    if(!b) return a;
    return gcd(b,a%b);
}

LL T;
LL n,k;

int main()
{
    int kase = 0;
    T = read();
    while(T--)
    {
        ++kase;
        n = read(),k = read();
        LL fz = Pow(2,k)-k-1;
        LL fm = Pow(2,k);
        LL ys = gcd(fz,fm);
        fm/=ys,fz/=ys;
        printf("Case #%d: %lld/%lld\n",kase,fz,fm);
    }
}

 

UVA1363

Description

给你n和k,
计算
for(int i=1;i<=n;i++) ans+=k%i;
输出ans
n,k∈[1,10^9]

Solution

简单的整除分块

和一道远古省选题一样

#include<bits/stdc++.h>

using namespace std;

inline long long read()
{
    long long f=1,x=0;
    char ch;
    do
    {
        ch=getchar();
        if(ch=='-');
    }while(ch<'0'||ch>'9');
    do
    {
        x=(x<<3)+(x<<1)+ch-'0';
        ch=getchar();
    }while(ch>='0'&&ch<='9');
    return f*x;
} 

long long n,k;

int main()
{
    while(scanf("%lld%lld",&n,&k)==2)
    {
        long long ans=n*k;
        long long r=0;
        for(long long l=1;l<=n;l=r+1)
        {
            if(k/l!=0) r=min(k/(k/l),n);
            else r=n;
            ans-=(r-l+1)*(k/l)*(r+l)/2;
        }
        cout<<ans<<endl;
    }
}

 

UVA11895

Description

在一次抽奖活动中,有n个抽奖箱。第i个抽奖箱有ti个信封,其中li个信封里面有奖。所有人排队抽奖,每次抽完奖都把信封丢回原来的箱子里。每个人都知道上述数据,都很聪明,但是并不知道前面的人中奖没有。求第k个人中奖的概率。

Solution

大水题

拿个优先队列动态维护一波最优概率即可

#include<bits/stdc++.h>

using namespace std;

#define LL long long

inline LL read()
{
    LL f = 1,x = 0;
    char ch;
    do
    {
        ch = getchar();
        if(ch == '-') f = -1;
    }while(ch < '0'||ch > '9');
    do
    {
        x = (x<<3) + (x<<1) + ch - '0';
        ch = getchar();
    }while(ch >= '0'&&ch <= '9');
    return f*x;
}

inline LL gcd(LL a,LL b)
{
    if(!b) return a;
    else return gcd(b,a%b);
}

int T;
LL n,k;

struct node
{
    LL p,q,t;
    friend bool operator < (node a1,node a2)
    {
        return a1.p * a2.q < a2.p * a1.q;
    }
};

priority_queue<node>pq;

int main()
{
    T = read();
    while(T--)
    {
        n = read();k = read();
        for(int i=1;i<=n;i++) 
        {
            LL t = read(),l = read();
            LL ys = gcd(t,l);
            node a;
            a.p = l/ys;a.q = t/ys;a.t = t;
            pq.push(a);
        }    
        for(int i=1;i<k;i++)
        {
            node u = pq.top();
            pq.pop();
            u.p *= (u.t - 1);
            u.q *= u.t;
            LL ys = gcd(u.p,u.q);
            u.p/=ys;u.q/=ys;
            pq.push(u);
        }
        printf("%lld/%lld\n",pq.top().p,pq.top().q);
        while(pq.size()) pq.pop();
    }
}

 

posted @ 2020-08-04 19:38  wlzs1432  阅读(163)  评论(0编辑  收藏  举报