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 ",ans1,ans2); } }
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 ",dp[len]); } }
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 ",ans); } }
UVA 1639
Description
有两个盒子各有n (n<=2e5) 个糖,每天随机选一个(概率分别为p,1-p),然后吃一颗糖。直到有一天,打开盒子一看,没糖了!输入n,p,求此时另一个盒子里糖的个数的数学期望。
Solution
假设没糖的是第一个盒子,那么第一个盒子拿了n+1次,第二个盒子拿了0次到n次,我们可以假设第二个盒子最终剩了i颗糖,这个时候概率显然就是
$ inom{2n-i}{n} p^{n+1} imes (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 ",++C,ans); } }
UVA 11971
Description
在直线上随机取k个点,分成的k+1段拼起来能组成多边形的概率
Solutuon
能组成多边形的条件是最大边要小于其他边之和
于是可以知道最大边长度要小于n/2
就像CSPd2t1一样从反面考虑,当不能组成多边形时大于n/2的边只能有一条
我们先假设最长边以左边为起点,于是剩下的点都只能在中点往右才不能组成多边形,此时概率为 $ frac{1}{2^{k}} $
且对于每种情况,最长边可以向右平移,一共有k+1种放法
所以答案就是 $ 1-(k+1) imes 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 ",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 ",pq.top().p,pq.top().q); while(pq.size()) pq.pop(); } }