银牌题:
ZOJ 3981 |
题目大意:n个队伍围成 一个圈比赛,一个有m个队伍参加,给n个队伍的位置,和哪个队伍在第几分钟过题,现在有一个小机器人,每一分钟他移动一步转圈发气球,当他到达的队伍有过题就会给他一个气球,一个队伍会有一个不开心度,为得到气球和过题的时间差,机器人初始位置不确定,总不开心度最小为多少。
题目思路:贪心。
首先第一想法就是枚举每个位置分别计算,但是这样超时。 那么假如起始位置确定,可不可以计算出总贡献呢,答案是可以的。细细观察可以发现,每个过题的不开心度,一定小于m,当一个队过了题,机器人要么还没走到他,要么刚刚走过他,所以最差情况也就m-1,所以先选取位置1前一个作为起点,那么每个队伍的不开心度是可以确定下来的,就是看过这个题的时间现在机器人的位置和队伍位置的差值也就是(pos[i] - (b)%m + m )%m 。
然后起始位置肯定选在这些过题队伍的位置,挨个枚举的话一定会出大问题,刚刚已经得到一个从0上一个开始的不开心度,按照不开心度排序,那么就是过题时间和队伍位置间隔的差值。当枚举到一个位置的时候,可以发现,前边的都比这个当前这个间隔小,后边的都比这个间隔大,所以统一缩小这个间隔的话,前边那群小的还要再补一个m。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll MAXN = 1e5+5;
ll a[MAXN],pos[MAXN],ac,id;
int main()
{
ll t;
scanf("%lld",&t);
while(t--){
ll n,m,p;
scanf("%lld%lld%lld",&n,&m,&p);
for(ll i=1;i<=n;i++){
scanf("%lld",&pos[i]);
pos[i]--;
}
ll sum = 0;
for(ll i=1;i<=p;i++){
scanf("%lld%lld",&id,&ac);
a[i] = (pos[id] - (ac)%m + m) %m;
sum += a[i];
}
ll Max = sum;
sort(a+1,a+1+p);
for(ll i=1;i<=p;i++){
ll now = sum - p*a[i] + (i-1)*m;
Max = min(Max,now);
}
printf("%lld\n",Max);
}
}
157 / 992 | G | ZOJ 3987 | Numbers |
题目大意:给一个大整数,拆成m个数字相加,让这m个数字按位或最小,最小能是多小。
题目思路:很明显的贪心了,一开始想的先拆成二进制,然后从高位往后,一个1拆两个1,如果这一位不能再拆,就加上这一位的贡献,但是其实并没有这么麻烦,可以直接从高位往低位走一波,如果这一位的低位全1比n还大,那就没必要放这个1,相反就有必要放。
import java.util.*;
import java.math.*;
public class Main {
public static BigInteger wei[] = new BigInteger[5005];
public static void init()
{
wei[1] = BigInteger.valueOf(1);
wei[0] = BigInteger.valueOf(0);
for(int i=2;i<=5000;i++) {
wei[i] = wei[i-1].multiply(BigInteger.valueOf(2));
}
for(int i=2;i<=5000;i++) {
wei[i] = wei[i].add(wei[i-1]);
}
}
public static void main(String [] arg) {
init();
Scanner cin = new Scanner(System.in);
int T;
T=cin.nextInt();
while(T-->0) {
BigInteger ans = BigInteger.valueOf(0);
BigInteger a = cin.nextBigInteger();
BigInteger b = cin.nextBigInteger();
int Max = 0;
for(int i=0;i<5000;i++) {
if(wei[i].compareTo(a)>0) {
Max = i;
break;
}
}
for(int i=Max ; i>=1;i--) {
if(a.compareTo(wei[i-1].multiply(b))<=0)continue;
BigInteger now = wei[i].subtract(wei[i-1]);
ans = ans.add(now);
BigInteger bei = a.divide(now);
if(bei.compareTo(b)>0) {
a=a.subtract(now.multiply(b) );
}
else {
a=a.subtract(now.multiply(bei) );
}
}
System.out.println(ans);
}
}
}
铜牌题:
221 / 603 | E | ZOJ 3985 |
题目思路:这个家伙最多放1个字母,因为我们可以发现,不管怎么插入字母最多只能有1的贡献,所以当没必要买第二个,那么这个题就转变成了能不能插入一个字母使得多1,也就几种情况判断一下。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int MAXN = 2e5+5;
char C[MAXN];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n;
scanf("%d",&n);
scanf("%s",C+1);
int num = 0;
for(int i=1;i<=n;i++){
if(i+3<=n && C[i] == 'C' && C[i+1] == 'C' && C[i+2] == 'P' && C[i+3] == 'C'){
num++;
}
}
bool f=0;
if(3<=n &&C[1] == 'C' && C[2] == 'P' && C[3] == 'C')f=1;
if(n-2>=1 &&C[n] == 'P' && C[n-1] == 'C' && C[n-2] == 'C')f=1;
for(int i=1;i<=n;i++){
if(i+3<=n && C[i] == 'C' && C[i+1] == 'C' && C[i+2] == 'P' && C[i+3] == 'P')f=1;
if(i+3<=n && C[i] == 'P' && C[i+1] == 'C' && C[i+2] == 'P' && C[i+3] == 'C')f=1;
if(i+2<=n && C[i] == 'C' && C[i+1] == 'C' && C[i+2] == 'C'){
if(i+4<=n && C[i+3]=='P' && C[i+4] == 'C'){
}
else f=1;
}
}
if(f)printf("%d\n",num+1);
else printf("%d\n",num);
}
}
196 / 905 | M | ZOJ 3993 | Safest Buildings |
这个就更水了,讲的是一个R的安全区,会缩小成一个半径为r的安全区,圆心不一定,问那么城市最安全,一个城市想要安全考虑圆心落在哪里就行了,一个城市画一个r的圈圈,和原点半径为R-r的画一个圈圈,交的部分就是圆心可选范围。排序
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int MAXN = 2e5+5;
struct node
{
int x,y,id;
double r;
node(){r = 0;}
node(int a,int b){
x = a;y = b;
}
}C[MAXN];
double dis(node a,node b)
{
return sqrt( (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y) );
}
double fun(node a, double r1, node b, double r2)
{
double d = sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
if (d >= r1+r2)
return 0;
if (r1>r2)
{
double tmp = r1;
r1 = r2;
r2 = tmp;
}
if(r2 - r1 >= d)
return M_PI*r1*r1;
double ang1=acos((r1*r1+d*d-r2*r2)/(2*r1*d));
double ang2=acos((r2*r2+d*d-r1*r1)/(2*r2*d));
return ang1*r1*r1 + ang2*r2*r2 - r1*d*sin(ang1);
}
bool cmp(node a,node b)
{
if(fabs(a.r - b.r) < 1e-8){
return a.id<b.id;
}
return a.r>b.r;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,R,r;
scanf("%d%d%d",&n,&R,&r);
for(int i=1;i<=n;i++){
C[i].id = i;
scanf("%d%d",&C[i].x,&C[i].y);
C[i].r= 0;
}
node now(0,0);
for(int i=1;i<=n;i++){
C[i].r = fun(C[i],r,now,R-r);
//cout<<i<<" * "<<C[i].r<<" ++++ "<<endl;
}
sort(C+1,C+1+n,cmp);
double Max = C[1].r;
int cnt = 0;
for(int i=1;i<=n;i++){
if(fabs(C[i].r - Max) <1e-9 ){
cnt++;
}
else break;
}
printf("%d\n",cnt);
for(int i=1;i<=cnt;i++){
if(fabs(C[i].r - Max) <1e-9 ){
printf("%d%c",C[i].id,(i==cnt)?'\n':' ');
}
else break;
}
}
}