C
题意:有n颗蓝彗星和红彗星,每颗星持续的时间都为t,给定每颗星星出现的时间,求只能看见蓝彗星的时长。
思路:求出有星星的时间和红星星持续的时间,只能看见蓝星星的时长=有星星的时间-红星星持续的时间。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxx = 1e5 + 10;
const int inf=0x3f3f3f3f;
int n,t;
struct node{
char col;
int start,end;
}a[maxx];
bool cmp(node a,node b)
{
if(a.start==b.start) return a.end<b.end;
return a.start<b.start;
}
void solve()
{
scanf("%d %d",&n,&t);
getchar();
for(int i=1;i<=n;i++) scanf("%c",&a[i].col);
//for(int i=1;i<=n;i++) cout<<a[i].col<<' ';
//cout<<'\n';
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i].start);
a[i].end=a[i].start+t;
}
sort(a+1,a+n+1,cmp);
int ans=0;
int last=-1,T=0;
for(int i=1;i<=n;i++)//区间合并
{
if(a[i].start>last)
{
T+=a[i].end-a[i].start;
last=a[i].end;
}
else if(a[i].end>last)
{
T+=a[i].end-last;
last=a[i].end;
}
}
last=-1;
int Tr=0;
for(int i=1;i<=n;i++)//区间合并
{
if(a[i].col=='R')
{
if(a[i].start>last)
{
Tr+=a[i].end-a[i].start;
last=a[i].end;
}
else if(a[i].end>last)
{
Tr+=a[i].end-last;
last=a[i].end;
}
}
}
ans=T-Tr;
printf("%d",ans);
}
int main()
{
int _t=1;
//scanf("%d", &_t);
while (_t--)
{
solve();
}
system("pause");
}
差分与前缀和的做法:
#include<bits/stdc++.h>
using namespace std;
int n,k;
string s;
int sum1[202020],sum2[202020];//蓝星星,红星星
int main(){
int i,x;
cin>>n>>k;
string s;
cin>>s;
for(i=0;i<n;i++){
cin>>x;
if(s[i]=='B')sum1[x]++,sum1[x+k]--;//x时刻蓝星星++,x+k时刻蓝星星--
else sum2[x]++,sum2[x+k]--;//x时刻红星星++,x+k时刻红星星--
}
int res=0;
//求前缀和
for(i=1;i<=2e5;i++)sum1[i]+=sum1[i-1],sum2[i]+=sum2[i-1],res+=(sum1[i]&&!sum2[i]);//只有蓝,答案++
cout<<res;
}
D
题意:求固定点到折线的最短距离,可以拆分成点到线段的最短距离
思路:点到线段的最短距离为以下两种情况中的一种:点到直线的最短距离,点到线段两端的最短距离。当点向直线作垂线,垂足不在线段上时为第二种情况。
如何判断第二种情况?把点C和线段两个端点A,B连接成三角形。当角A或角B为钝角时,为第二种情况。
如何求点C到直线AB的距离h?AB*h/2=S
三角形面积可以直接用海伦公式: , p=(a+b+c)/2。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxx = 2e5 + 10;
const int inf=0x3f3f3f3f;
struct point{
double x,y;
point(double x,double y):x(x),y(y){}
};
double dis(point A,point B)//点AB距离
{
return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}
double S(point A,point B,point C)//三角形ABC面积
{
double a=dis(B,C),b=dis(A,C),c=dis(A,B);//三条边长
double p=(a+b+c)/2.0;
return sqrt(p*(p-a)*(p-b)*(p-c));
}
bool judge(point A,point B,point C)//判断A是否是钝角
{
double a=dis(B,C),b=dis(A,C),c=dis(A,B);
if(a*a>b*b+c*c) return true;
else return false;
}
double fun(point A,point B,point C)//点C到线段AB的距离
{
if(judge(A,B,C)||judge(B,A,C))//若A为钝角或B为钝角
{
double d1=dis(C,A),d2=dis(C,B);//点C到线段的两端点的距离
return min(d1,d2);
}
else//点C到直线AB的距离
{
double s=S(A,B,C);//求三角形ABC的面积
double d3=2.0*s/dis(A,B);//点C到直线AB的距离
return d3;
}
}
void solve()
{
int n;
double x0,y0,x,y;//起点,固定点
cin>>n;
cin>>x0>>y0>>x>>y;
point start(x0,y0);
point st(x,y);
double ans=inf;
for(int i=1;i<=n;i++)
{
double xi,yi;
cin>>xi>>yi;
point tem(start.x+xi,start.y+yi);
ans=min(ans,fun(start,tem,st));//点st到线段start-tem的距离
start=tem;//更新起点
}
printf("%.8f",ans);
}
int main()
{
int _t=1;
//scanf("%d", &_t);
while (_t--)
{
solve();
}
system("pause");
}
F
题意:第二种记谱法和第一种不同的在于,尖括号’<‘代表后面所有的音比前面的音低 8 度。反尖括号'>'则代表后面所有的音比前面的音高 8 度。
思路:用一个变量统计当前八度的情况,然后对应哪个音直接输出即可,后面根据八度的情况来添加对应数量的'.'或者'*'即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxx = 1e5 + 10;
const int inf=0x3f3f3f3f;
int n,t;
string s[2]={{"01234567"},{"0CDEFGAB"}};
void solve()
{
string ss;
cin>>ss;
int std=0;
int len=ss.length();
for(int i=0;i<len;i++)
{
if(ss[i]=='<') std--;
else if(ss[i]=='>') std++;
else
{
switch(ss[i])
{
case 'C' :printf("1");break;
case 'D' :printf("2");break;
case 'E' :printf("3");break;
case 'F' :printf("4");break;
case 'G' :printf("5");break;
case 'A' :printf("6");break;
case 'B' :printf("7");break;
}
if(std>0)
{
for(int j=0;j<std;j++) printf("*");
}
else if(std<0)
{
for(int j=0;j<-std;j++) printf(".");
}
}
}
}
int main()
{
int _t=1;
//scanf("%d", &_t);
while (_t--)
{
solve();
}
system("pause");
}
H
思路:显然小紫选择正方体的中心,小红选择正方体的一角。题目转化成已知正方体体对角线的一半,求正方体体积。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxx = 1e6 + 10;
const int inf=0x3f3f3f3f;
void solve()
{
int x;
cin>>x;
double a=2.0*x/sqrt(3);
printf("%.7f",a*a*a);
}
int main()
{
int _t=1;
//scanf("%d", &_t);
while (_t--)
{
solve();
}
system("pause");
}
I
题意:n个物品,每个物品的花费是ai,价值bi。求花费为k的倍数的时候最大价值
思路:01背包。dp[i][j]表示考虑前i个物品,花费模k为j的情况下最大价值。注意负数取模时先+k再模k
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxx = 1010;
const int inf=0x3f3f3f3f;
int n,k;
int a[maxx];
int b[maxx];//a[i]是花费 b[i]是价值
ll dp[maxx][2020];//dp[i][j]表示考虑前i个物品,花费模k为j的情况下最大价值
void solve()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%d %d",&a[i],&b[i]);
a[i]%=k;
}
//初始化为负无穷,表示无法取到
for(int i=0;i<=n;i++)
{
for(int j=0;j<k;j++)
{
dp[i][j]=-1e16;
}
}
dp[0][0]=0;
for(int i=1;i<=n;i++)
{
for(int j=0;j<k;j++)
{
dp[i][(j+a[i])%k]=max(dp[i-1][(j+a[i])%k],dp[i-1][j]+b[i]);
//dp[i][j]=max(dp[i-1][j],dp[i-1][(j-a[i]%k+k)%k]+b[i]);//max(不取第i件,取第i件)注意负数取模时先+k再模k
}
}
if(dp[n][0]<=0) printf("-1");
else printf("%lld",dp[n][0]);
}
int main()
{
int _t=1;
//scanf("%d", &_t);
while (_t--)
{
solve();
}
system("pause");
}
K
题意:给定x,构造x的倍数y,且在二进制下,x是y的子串,x与y二进制表示中1的个数不同。
思路:注意x<=1e9,y<=1e19,1e9转化成二进制占30位,容易想到把x在二进制下重复写两次,最多占60位二进制(符合y<=1e19条件)。接下来证明此时y是x的倍数:把x在二进制下重复写两次即在x后补上若干个0后加上x。在x后补若干0即x乘若干个2,再加上x,结果y就是x的倍数。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxx = 1e6 + 10;
const int inf=0x3f3f3f3f;
ll x;
void solve()
{
scanf("%lld",&x);
int i=0;
//在x后补上 x在二进制下位数个 0
for(i=0;i<=30;i++)
{
if(1ll<<i>x) break;
}
cout<<x*(1ll<<i)+x;//补0加x
}
int main()
{
int _t=1;
//scanf("%d", &_t);
while (_t--)
{
solve();
}
system("pause");
}