开始刷多校,今天第一弹。
话说,多校的题目真的好难。。。
Median HDU 5857
给定一个有序序列,然后给定两个区间[l1,r1],[l2,r2]产生新的序列。
要求新序列的中位数。
分三种情况考虑。
1.区间没交集。
2.区间半交。
3.区间全包裹。
各自找到自己的位置就好。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int a[100005];
int T,n,m,l1,l2,r1,r2;
double find(int a[],int x){
if(r1<=l2){
if(x<=r1-l1+1) return a[l1+x-1];
else return a[l2+x-1-r1+l1-1];
}
else if(r1<=r2){
if(x<=l2-l1) return a[l1+x-1];
else if(x>r1-l1+1+r1-l2+1) return a[l2+x-r1+l1-1-1];
else return a[l2+(x-l2+l1+1)/2-1];
}
else{
swap(r1,r2); // l1,r2,r1,l2
if(x<=l2-l1) return a[l1+x-1];
else if(x>r1-l1+1+r1-l2+1) return a[l2+x-r1+l1-1-1];
else return a[l2+(x-l2+l1+1)/2-1];
}
}
int main(){
cin>>T;
while(T--){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",a+i);
for(int i=1;i<=m;i++){
scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
int len = r1-l1+1 + r2-l2+1;
if(l1>l2){
int t =l1;l1=l2;l2=t;
t =r1;r1=r2;r2=t;
}
double mid;
if(len&1) mid = find(a,len/2+1);
else mid = 0.5*find(a,len/2) + 0.5*find(a,len/2+1);
printf("%.1lf\n",mid);
}
}
return 0;
}
Hard problem
解析几何吧。先建系算出交点的坐标,然后就能算出来了。
#include <cstdio>
#include <cmath>
#include <iostream>
using namespace std;
double calc(int l){
double t1 = asin(sqrt(14.0)/8.0);
double t2 = asin(sqrt(14.0)/4.0);
double s2 = l * l * 1.0 / 8 * t2 * 2;
double s1 = l * l * 1.0 / 2 * t1 * 2 - sqrt(7) / 8 * l * l;
return (s2 - s1)*2.0;
}
int main(){
int T,l;
cin>>T;
while(T--){
cin>>l;
printf("%.2lf\n",calc(l));
}
return 0;
}
Death Sequence
动规题。
先算i在第几轮死掉。有方程f[i]=i%k?f[i-i/k-1]+1:0;
然后累计前面死的人的个数就好了。
前几轮死的人说 a[i]=i%k?a[i-i/k-1]:i/k+1;
加上预处理的left[f[i]]即可。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 3000010;
int ans[MAXN],f[MAXN],a[MAXN],LEFT[MAXN];
int T,n,k,q,x;
void solve(){
int t = n;
int tot = 0;
LEFT[0] = 0;
while(t){
tot++;
LEFT[tot] = LEFT[tot-1]+(t-1)/k+1;
t-=(t-1)/k+1;
}
memset(f,0,sizeof(f));
memset(a,0,sizeof(a));
for(int i=0;i<n;i++){
f[i]=(i%k)?f[i-i/k-1]+1:0;
a[i]=(i%k)?a[i-i/k-1]:i/k+1;
}
for(int i=0;i<n;i++){
int t=LEFT[f[i]]+a[i];
ans[t]=i;
}
}
int main(){
cin>>T;
while(T--){
memset(ans,0,sizeof(ans));
scanf("%d%d%d",&n,&k,&q);
solve();
for(int i=1;i<=q;i++){
scanf("%d",&x);
printf("%d\n",ans[x]+1);
}
}
return 0;
}
Counting Intersections
给定一系列平行于坐标轴的直线,求其交点的个数。
参考线段树扫描线做法。
对于横着的线段,左端点+1,右端点-1。这样累计的时候可以巧妙的去掉没有交点的线。对于竖着的线段,就查询。
处理的时候需要离散化。
以及ans要用long long
#include <cstdio>
#include <cstring>
#include <iostream>
#include <climits>
#include <algorithm>
#include <map>
#define LL long long
using namespace std;
const int MAXN = 100005;
struct node{
int tp,x,y,y2;
}info[MAXN*2];
int a[MAXN*2],sum[MAXN*2],Maxn;
map<int,int> mp;
bool cmp(node a,node b){
return (a.x<b.x)||(a.x==b.x&&a.tp<b.tp);
}
void insert(int BIT,int tp,int x,int y,int y2){
info[BIT].tp=tp;
info[BIT].x = x;
info[BIT].y = y;
info[BIT].y2=y2;
}
int lowbit(int k){return k&(-k);}
void add(int k,int delta){
while(k<=Maxn){
sum[k]+=delta;
k+=lowbit(k);
}
}
int query(int k){
int s = 0;
while(k){
s+=sum[k];
k-=lowbit(k);
}
return s;
}
int main(){
int T,n;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
int tot=0,all=0;
for(int i=1;i<=n;i++){
int x1,y1,x2,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
if(x1==x2){//竖 1
if(y1>y2) swap(y1,y2);
insert(++tot,1,x1,y1,y2);
a[++all]=y1;
a[++all]=y2;
} else {//横 0
if(x1>x2) swap(x1,x2);
insert(++tot,0,x1,y1,1);
insert(++tot,0,x2+1,y2,-1);
a[++all]=y1;
}
}
sort(a+1,a+1+all);
int cnt = 0;
mp.clear();
for(int i=1;i<=all;i++)
if(!mp[a[i]]) mp[a[i]]=++cnt;
Maxn = cnt + 1;
memset(sum,0,sizeof(sum));
sort(info+1,info+1+tot,cmp);
LL ans = 0;
for(int i=1;i<=tot;i++){
if(info[i].tp==0){
int tp = mp[info[i].y];
add(tp,info[i].y2);
} else {
int l = mp[info[i].y],r=mp[info[i].y2];
ans += query(r) - query(l-1);
}
}
printf("%I64d\n",ans);
}
return 0;
}
Water problem
求 1~n 这n个数字的英文写法的总长度. (不算空格和连字符)
模拟题。
特殊处理1-19。20-1000的话直接算个位十位+百位就行了。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int bit1[] = {4,3,3,5,4,4,3,5,5,4,3,6,6,8,8,7,7,9,8,8};
int bit2[] = {0,0,6,6,5,5,5,7,6,6};
int hundred, thousand;
int cnt[1100];
void solve(){
hundred = 7; thousand = 8;
cnt[1000] = 11;
for(int i=1; i<1000; i++) {
if(i < 20) cnt[i] = bit1[i];
else if(i < 100){
int m = i;
cnt[i] = bit2[m/10];
if(m%10) cnt[i] += bit1[m%10];
}
else {
int m = i;
cnt[i] = bit1[m/100] + hundred;
if(!(m%100)) continue;
cnt[i] += cnt[m%100] + 3;
}
}
for(int i=1; i<=1000; i++) cnt[i] += cnt[i-1];
}
int main(){
solve();
int T;
cin>>T;
while(T--){
int n;
scanf("%d",&n);
printf("%d\n",cnt[n]);
}
return 0;
}