T1.xiz
分析:
题目描述不准确,不过样例很准确
考虑记一个
数组,
表示字符
与上一个和ta相同的字符在字符串中的距离,如果没有则记为0
这样T的
可以很容易的表示出来
但有个问题,在
中
数组是随着匹配位置变化的
这题一般有两种做法,一种是用kmp匹配,一种是哈希
网上dada的题解(果然是dada,看不大懂)
考虑随着匹配位置的移动把S的哈希值给改掉
记一个
数组,表示这个字符下一次会在哪里出现
这里就能看出为什么要求与之前的距离,因为这样可以随着移动通过
数组把不符合的值改掉
详细说,如果当前这个
的值指向匹配范围还要往后,直接将其指向的那个点的
值改为0即可
如果这个点正好在匹配的范围内,则要连带S的哈希值一起改
T2.yja
分析:
考场上yy出了60分做法
20%
正多边形
我们发现并没有什么特殊的三角形可以适合所有情况
考虑能不能得到一个函数的形式
手玩发现上述的公式有上凸性质,三分
即可
(
)
注意:任何一个
都有可能是图中所谓的
四个点的最大凸包有两种情况:
四个点都在凸包上,对角线互相垂直
一个点过于接近原点,转化成 的情况
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#define LD double
using namespace std;
const LD eps=1e-8;
const LD Pi=acos(-1.0);
const int N=10;
int n,m,nn;
LD r[N],a[N];
LD A,B,C;
LD Max(LD a,LD b) {
if (a-b>eps) return a;
else return b;
}
LD f(LD x) {
return (x+A)*((sqrt(B*B-x*x))+(sqrt(C*C-x*x)));
}
LD SF() {
LD l=0,r=min(B,C);
LD m1,m2;
while (r-l>=eps) {
m1=l+(r-l)/3.0;
m2=r-(r-l)/3.0;
if (f(m2)-f(m1)<eps) r=m2;
else l=m1;
}
return f((m1+m2)/2)/2.0;
}
LD solve_3() {
LD ans=0;
A=a[1]; B=a[2]; C=a[3];
ans=Max(ans,SF());
A=a[2]; B=a[1]; C=a[3];
ans=Max(ans,SF());
A=a[3]; B=a[1]; C=a[2];
ans=Max(ans,SF());
return ans;
}
LD solve_4() {
LD ans=0;
LD t=((r[1]+r[2])*(r[3]+r[4]))/2.0;
ans=Max(ans,t);
t=((r[1]+r[3])*(r[2]+r[4]))/2.0;
ans=Max(ans,t);
t=((r[1]+r[4])*(r[2]+r[3]))/2.0;
ans=Max(ans,t);
sort(r+1,r+1+4);
a[1]=r[2]; a[2]=r[3]; a[3]=r[4];
ans=Max(ans,solve_3());
return ans;
}
void solve() {
LD b=(2.0*Pi)/(LD)n;
LD ans=0;
ans=(r[1]*r[1]*sin(b))/2.0;
ans=ans*(LD)n;
printf("%0.7lf\n",(double)ans);
}
int main()
{
freopen("yja.in","r",stdin);
freopen("yja.out","w",stdout);
scanf("%d",&n);
bool flag=1;
for (int i=1;i<=n;i++) {
scanf("%lf",&r[i]),a[i]=r[i];
if (i!=1) {
if (fabs(r[i]-r[i-1])>eps) flag=0;
}
}
if (n<=2) printf("%0\n");
else if (flag) solve();
else if (n==3) printf("%0.7lf\n",(double)solve_3());
else if (n==4) printf("%0.7lf\n",(double)solve_4());
return 0;
}
100%
枚举在凸包上是哪些点以及顺序,面积为
条件是
拉格朗日乘数有
关于
单调
于是二分出
,算出
T3.zkb
分析:
40%
1e14一位的高精度(思路来源)
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll unsigned long long
using namespace std;
const ll mod=1e14;
const int N=20005;
int n,m;
ll a[N],ans[201],o;
int cmp(const ll &a,const ll &b) {
return a>b;
}
void sort_down(int l,int r) {
sort(a+l,a+r+1,cmp);
}
void sort_up(int l,int r) {
sort(a+l,a+r+1);
}
void solve(int l,int r) {
for (int i=0;i<201;i++) ans[i]=0LL;
ans[1]=1LL;
int d=1;
for (int i=l;i<=r;i++) {
for (int j=1;j<=d;j++)
ans[j]=(ll)ans[j]*a[i];
for (int j=1;j<=d;j++) {
ans[j+1]=ans[j+1]+ans[j]/mod;
ans[j]=ans[j]%mod;
}
if (ans[d+1]>0) d++;
while (ans[d]>mod) {
ans[d+1]=ans[d+1]+ans[d]/mod;
ans[d]=ans[d]%mod;
d++;
}
}
o=ans[d];
while (o>=10) o=o/(ll)10;
printf("%lld\n",o);
}
int main()
{
freopen("zkb.in","r",stdin);
freopen("zkb.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
int opt,x,y,z;
while (m--) {
scanf("%d%d%d",&opt,&x,&y);
if (opt==1) {
scanf("%d",&z);
if (z==0) sort_down(x,y);
else sort_up(x,y);
}
else {
solve(x,y);
}
}
return 0;
}
100%
乘法好烦,但是我们可以乘除变加减(取对数),并且最高位可以直接计算
于是问题转化为区间排序并维护区间和
一个显然的想法是对每一个点开一棵值域线段树,再在全局用一个大线段树维护每个值域线段树之间的关系
排序操作相当于将两端未完全覆盖的值域线段树分裂,同时将中间的值域线段树合并,询问时只要全局线段树中维护一下和就可以了
显然只会有
次分裂与合并