BestCoder Round #91

35 篇文章 0 订阅
27 篇文章 0 订阅

Lotus and Characters

 
 Accepts: 150
 
 Submissions: 897
 Time Limit: 2000/1000 MS (Java/Others)
 
 Memory Limit: 262144/131072 K (Java/Others)
问题描述
Lotus有nn种字母,给出每种字母的价值以及每种字母的个数限制,她想构造一个任意长度的串。
定义串的价值为:第1位字母的价值*1+第2位字母的价值*2+第3位字母的价值*3……
求Lotus能构造出的串的最大价值。(可以构造空串,因此答案肯定\geq 00
输入描述
第一行是数据组数T(0 \leq T \leq 1000)T(0T1000)。
对于每组数据,第一行一个整数n(1 \leq n \leq 26)n(1n26),接下来nn行,每行2个整数val_i,cnt_i(|val_i|,cnt_i\leq 100)vali,cnti(vali,cnti100),分别表示第ii种字母的价值和个数限制。
输出描述
对于每组数据,输出一行一个整数,表示答案。
输入样例
2
2
5 1
6 2
3
-5 3
2 1
1 1
输出样例
35
5

题解:模拟+贪心

这道题容易忽略的一点就是负数不一定不入选。因为可以通过在前面补负数,使后面正数的系数变大。

我们将所有的元素从大到小排序,然后倒叙插入(就是先插入的系数会大),如果到某一时刻答案变小,就停止。

最后输出峰值即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 10000
using namespace std;
int n,a[N];
int cmp(int x,int y)
{
    return x>y;
}
int main()
{
	freopen("a.in","r",stdin);
	freopen("std.out","w",stdout);
    int T; scanf("%d",&T);
    for (int t=1;t<=T;t++) {
        scanf("%d",&n);
        int cnt=0;
        for (int i=1;i<=n;i++) {
            int val,x;
            scanf("%d%d",&val,&x);
            for (int j=1;j<=x;j++) a[++cnt]=val;
        }
        sort(a+1,a+cnt+1,cmp);
        int sum=0; int ans=0; int mx=0;
        for (int i=1;i<=cnt;i++) {
            ans+=a[i]+sum;
            sum+=a[i];
            if (ans<mx) break;
            mx=ans;
        }
        printf("%d\n",mx);
    }
}




Lotus and Horticulture

 
 Accepts: 91
 
 Submissions: 641
 Time Limit: 4000/2000 MS (Java/Others)
 
 Memory Limit: 262144/262144 K (Java/Others)
问题描述
这几天Lotus对培养盆栽很感兴趣,于是她想搭建一个温室来满足她的研究欲望。
Lotus将所有的nn株盆栽都放在新建的温室里,所以所有盆栽都处于完全相同的环境中。
每一株盆栽都有一个最佳生长温度区间[l,r][l,r],在这个范围的温度下生长会生长得最好,但是不一定会提供最佳的研究价值(Lotus认为研究发育不良的盆栽也是很有研究价值的)。
Lotus进行了若干次试验,发现若第ii株盆栽的生长温度适宜,可以提供a_iai的研究价值;若生长温度超过了适宜温度的上限,能提供b_ibi的研究价值;若生长温度低于适宜温度的下限,则能提供c_ici的研究价值。
现在通过试验,Lotus已经得知了每一株盆栽的适宜生长温度范围,也知道了它们的aabbcc的值。你需要根据这些信息,给温室选定一个温度(这个温度可以是任意实数),使得Lotus能获得的研究价值最大。
输入描述
多组数据,第一行一个整数TT表示数据组数
每组数据第一行一个整数n\in[1,50000]n[1,50000],表示盆栽数量
接下来nn行每行五个整数l_i,r_i,a_i,b_i,c_i\in[1, 10^9]li,ri,ai,bi,ci[1,109],意义如上所述
输出描述
每组数据输出一行一个整数表示答案
输入样例
1
5
5 8 16 20 12
10 16 3 13 13
8 11 13 1 11
7 9 6 17 5
2 11 20 8 5
输出样例
83
题解:差分

当时写的线段树,TLE了

其实差分就可以。我们对于每个植物维护四个时间点,区间的左右端点,和左端点-0.5,右端点+0.5.

将所有的时间*2,就可以将所有的实数变成小数。

然后进行离散化,维护一个tr数组。设初始时的温度为-INF,那么此时的答案就是sigma ci

如果当前到达了一个区间的左端点,那么对总答案的影响是+(ai-ci)

如果到达区间右端点+0.5,那么对总答案的影响是+(bi-ai)

所有我们将所有的影响统计到tr数组中,那么tr数组的前缀和就是这个温度的答案。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define N 500003
#define LL long long 
using namespace std;
int n,m,x[N],y[N],q[N],a[N],b[N],c[N];
LL val[N];
int main()
{   
    int T; scanf("%d",&T);
    for (int t=1;t<=T;t++) {
        memset(val,0,sizeof(val));
        scanf("%d",&n);
        int cnt=0;
        for (int i=1;i<=n;i++) {
            scanf("%d%d%d%d%d",&x[i],&y[i],&a[i],&b[i],&c[i]);
            x[i]*=2; y[i]*=2;
            q[++cnt]=x[i]; q[++cnt]=y[i]; q[++cnt]=x[i]-1; q[++cnt]=y[i]+1;
        }
        sort(q+1,q+cnt+1);
        cnt=unique(q+1,q+cnt+1)-q-1;
        LL ans=0;
        for (int i=1;i<=n;i++) {
            x[i]=lower_bound(q+1,q+cnt+1,x[i])-q;
            y[i]=lower_bound(q+1,q+cnt+1,y[i])-q;
            val[x[i]]+=(LL)(a[i]-c[i]);
            val[y[i]+1]+=(LL)(b[i]-a[i]);
            ans+=(LL)c[i];
        }
        LL mx=ans;
        for (int i=1;i<=cnt;i++) {
            val[i]+=val[i-1];
            mx=max(mx,ans+val[i]);
        }
        printf("%I64d\n",mx);
    }
}



Lotus and Thermodynamics

 
 Accepts: 0
 
 Submissions: 144
 Time Limit: 6000/3000 MS (Java/Others)
 
 Memory Limit: 262144/262144 K (Java/Others)
问题描述
这几天Lotus对布朗运动很感兴趣,于是她想编一个模拟程序来满足她的研究欲望。
这个程序的目的是模拟一个二维平面上一些点的无规律运动,需要支持以下几种操作:
I x y : 表示在平面中出现了一个新的点(x,y)(x,y),编号为平面中已有的点数+1。
M l r x y : 表示编号属于[l,r][l,r]的点进行了位移(x,y)(x,y)。
R l r x y a : 表示编号属于[l,r][l,r]的点关于点(x,y)(x,y)逆时针旋转了角度aa。其中aa表示为弧度制,且aa仅包含一位小数。
F l r x y d : 表示编号属于[l,r][l,r]的点以点(x,y)(x,y)为中心缩放dd倍,保证d\in[0,1]d[0,1]dd仅包含一位小数。
Q id : 询问编号为idid的点的坐标,输出一行两个实数,用一个空格分开,用floor()取整到个位。即假如答案是x,y,就用printf("%.0lf %.0lf\n",floor(x),floor(y))来输出。
输入描述
多组数据,第一行一个整数TT表示数据组数。
每组数据第一行一个整数q\in[1,100000]q[1,100000],表示操作个数
接下来qq行,每行描述一个操作,格式如上所述
对于所有出现在输入文件里的数,保证它们属于[-1000,1000][1000,1000]
保证q > 10000q>10000的数据不超过2组。
输出描述
对于每个QQ操作,用上面所述方法输出答案。保证答案中点的坐标绝对值小于10^7107
输入样例
2
6
I 4 -1
I 8 3
R 1 1 -4 8 -0.4
Q 1
F 1 2 -1 1 0.1
I -1 9
5
I 0 4
R 1 1 -6 9 1.9
Q 1
R 1 1 1 8 2.4
Q 1
输出样例
-1 -4
-4 16
-2 -1

题解:线段树+矩阵

就是对于每个点维护一个矩阵,然后每次修改相当于乘上一个矩阵
对于一个点我们维护<sx,sy,1>,其中sx,sy是点的横纵坐标。

平移操作(x,y) 可以得到<sx+x,sy+y,1> 那么区间的标记矩阵为

1 0 0

0 1 0

x y 1

放缩操作(x,y) 可以得到<x+(sx-x)*d,y+(sy-y)*d,1>,那么区间的标记矩阵为

d    0    0 

0    d    0

x-dx y-dy 1

旋转操作(x,y) 可以得到<(sx-x)*cos-(sy-y)*sin+x,(sx-x)*sin+(sy-y)*cos+y,1> 那么区间的标记矩阵为

cos          sin          0

-sin         cos          0

-xcos+ysin+x -xsin-ycos+y 1

然后问题就变成了线段树的区间修改点查询

但是这道题的精度貌似有些问题,所有目前没有人可以A掉。。。

这里的思路和代码仅供参考。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define N 100003
using namespace std;
struct matrix{
	double b[4][4];
};
struct data {
	matrix a,delta;
}tr[N*4];
double e[4][4];
int n;
struct node {
	int opt,l,r,id;
	double x,y,val;
}a[N];
void clear(matrix &a)
{
	for (int i=1;i<=3;i++)
	 for (int j=1;j<=3;j++) a.b[i][j]=0;
    for (int i=1;i<=3;i++) a.b[i][i]=1;
}
void pointchange(int now,int l,int r,int x,double px,double py)
{
	if (l==r) {
		tr[now].a.b[1][1]=px;
		tr[now].a.b[1][2]=py;
		tr[now].a.b[1][3]=1;
		clear(tr[now].delta);
		//cout<<now<<" "<<px<<" "<<py<<endl;
		//for (int i=1;i<=3;i++) printf("%.0lf ",tr[now].a.b[1][i]);
		//cout<<endl;
		return;
	}
	int mid=(l+r)/2;
	clear(tr[now].delta);
	if (x<=mid) pointchange(now<<1,l,mid,x,px,py);
	else pointchange(now<<1|1,mid+1,r,x,px,py);
}
matrix mul(matrix a,matrix b)
{
	matrix c;
	for (int i=1;i<=3;i++)
	 for (int j=1;j<=3;j++){
	 	c.b[i][j]=0;
	 	for (int k=1;k<=3;k++)
	 	 c.b[i][j]+=a.b[i][k]*b.b[k][j];
	 }
	return c;
}
bool check(matrix a)
{
	for (int i=1;i<=3;i++)
	 for (int j=1;j<=3;j++)
	  if (a.b[i][j]!=e[i][j]) return true;
	return false; 
}
void pushdown(int now)
{
	if (check(tr[now].delta)) {
		tr[now<<1].a=mul(tr[now<<1].a,tr[now].delta);
		tr[now<<1|1].a=mul(tr[now<<1|1].a,tr[now].delta);
		tr[now<<1].delta=mul(tr[now<<1].delta,tr[now].delta);
		tr[now<<1|1].delta=mul(tr[now<<1|1].delta,tr[now].delta);
		clear(tr[now].delta);
	}
}
void query(int now,int l,int r,int ll,int rr,matrix t)
{
	if (ll<=l&&r<=rr) {
		//for (int i=1;i<=3;i++) cout<<tr[now].a.b[1][i]<<" ";
		//cout<<endl;
		tr[now].a=mul(tr[now].a,t);
		tr[now].delta=mul(tr[now].delta,t);
		return;
	}
	int mid=(l+r)/2;
	pushdown(now);
	if (ll<=mid) query(now<<1,l,mid,ll,rr,t);
	if (rr>mid) query(now<<1|1,mid+1,r,ll,rr,t);
}
data find(int now,int l,int r,int x)
{
	if (l==r) return tr[now];
	int mid=(l+r)/2;
    pushdown(now);
	if (x<=mid) return find(now<<1,l,mid,x);
	else return find(now<<1|1,mid+1,r,x); 
}
int main()
{
	freopen("a.in","r",stdin);
	freopen("my.out","w",stdout);
	int T; scanf("%d",&T);
	for (int i=1;i<=3;i++) e[i][i]=1;
	for (int t=1;t<=T;t++) {
		scanf("%d",&n);
		int cnt=0;
		for (int i=1;i<=n;i++) {
			char s[3]; scanf("%s",s);
			if (s[0]=='I') {
				a[i].opt=1; 
				scanf("%lf%lf",&a[i].x,&a[i].y);
				++cnt;
			}
			if (s[0]=='M') {
				a[i].opt=2;
				scanf("%d%d%lf%lf",&a[i].l,&a[i].r,&a[i].x,&a[i].y);
			}
			if  (s[0]=='R') {
				a[i].opt=3;
				scanf("%d%d%lf%lf%lf",&a[i].l,&a[i].r,&a[i].x,&a[i].y,&a[i].val);
			}
			if (s[0]=='F') {
				a[i].opt=4; 
				scanf("%d%d%lf%lf%lf",&a[i].l,&a[i].r,&a[i].x,&a[i].y,&a[i].val);
			}
			if (s[0]=='Q') {
				a[i].opt=5; 
				scanf("%d",&a[i].id);
			}
		}
		int now=0;
		for (int i=1;i<=n;i++) {
			if (a[i].opt==1) now++,pointchange(1,1,cnt,now,a[i].x,a[i].y);
			if (a[i].opt==2) {
				matrix t; 
				t.b[1][1]=1; t.b[1][2]=0; t.b[1][3]=0;
				t.b[2][1]=0; t.b[2][2]=1; t.b[2][3]=0;
				t.b[3][1]=a[i].x; t.b[3][2]=a[i].y; t.b[3][3]=1;
				query(1,1,cnt,a[i].l,a[i].r,t);
			}
			if (a[i].opt==3) {
				matrix t;
				t.b[1][1]=cos(a[i].val); t.b[1][2]=sin(a[i].val); t.b[1][3]=0;
				t.b[2][1]=-sin(a[i].val); t.b[2][2]=cos(a[i].val); t.b[2][3]=0;
				t.b[3][1]=-a[i].x*cos(a[i].val)+a[i].y*sin(a[i].val)+a[i].x;
				t.b[3][2]=-a[i].x*sin(a[i].val)-a[i].y*cos(a[i].val)+a[i].y;
				t.b[3][3]=1;
				query(1,1,cnt,a[i].l,a[i].r,t);
			}
			if (a[i].opt==4) {
				matrix t;
				t.b[1][1]=a[i].val; t.b[1][2]=0; t.b[1][3]=0;
				t.b[2][1]=0; t.b[2][2]=a[i].val; t.b[2][3]=0;
				t.b[3][1]=a[i].x-a[i].val*a[i].x;
				t.b[3][2]=a[i].y-a[i].val*a[i].y;
				t.b[3][3]=1;
				query(1,1,cnt,a[i].l,a[i].r,t);
			}
			if (a[i].opt==5) {
			 data t=find(1,1,cnt,a[i].id);
			 printf("%.0lf %.0lf\n",floor(t.a.b[1][1]),floor(t.a.b[1][2]));
		    }
		}
    }
 }


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值