持续填坑中…
原题链接
做法:根据同弧所对圆周角相等。我们可以枚举一个点A,然后再枚举每个点B,求∠ABO的。将所有的∠ABO存起来,取一个众数。(这里要保证一点就是保证B在AO上方或者下方一个固定的地方,否则不是一个圆
#include
using namespace std;
typedef long long LL;
typedef __int128_t LLL;
#define N 2000 + 5
int n, ans = 1, X[N], Y[N];
struct Frac//分数
{
LL fz, fm;//分子,分母
Frac() : Frac(0, 1){}
Frac(LL fz, LL fm) : fz(fz), fm(fm) {}
bool operator < (const Frac &rhs)//重载分数小于
{
return (LLL) fz * rhs.fm < (LLL) fm * rhs.fz;
}
bool operator == (const Frac &rhs)//交叉相乘等于
{
return (LLL) fz * rhs.fm == (LLL) fm * rhs.fz;
}
}A[N];
int Cross(int lhs, int rhs)//向量差乘
{
return X[lhs] * Y[rhs] - X[rhs] * Y[lhs];
}
int Dot(int lhs, int rhs)//向量点乘
{
return X[lhs] * X[rhs] + Y[lhs] * Y[rhs];
}
int Dis2(int lhs, int rhs)//两点距离的平方
{
int dx = X[lhs] - X[rhs], dy = Y[lhs] - Y[rhs];
return dx * dx + dy * dy;
}
int Sgn(int x)//角的符号
{
if (x > 0) return 1;
if (x < 0) return -1;
return 0;
}
Frac GetCosAngle2(int i, int j)//求∠ABO
{
int a2 = Dis2(0, i), b2 = Dis2(i, j), c2 = Dis2(0, j);
int sgn = Sgn(b2 + c2 - a2);
return Frac(1LL * sgn * (b2 + c2 - a2) * (b2 + c2 - a2), 4LL * b2 * c2);
}
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i ++)
scanf("%d%d", X + i, Y + i);
for (int i = 1; i <= n; i ++)//枚举每一个点A
{
int cnt = 0;
for (int j = 1; j <= n; j ++)//再枚举每一个点B
if (Cross(i, j) > 0)
A[++ cnt] = GetCosAngle2(i, j);
sort(A + 1, A + cnt + 1);
for (int l = 1, r; l <= cnt; l = r)//求角度的众数
{
r=l;
while(A[l]==A[r] && r<=cnt){
r++;
}
ans = max(ans, r - l + 1);
}
}
printf("%d\n", ans);
return 0;
}
原题链接
题意:给你一个n个节点的无根树,现在要你找到最少的k条链使得这k条链能覆盖整个树边
#include
using namespace std;
const int maxn=2e5+10;
struct edge{
int v,next;
}e[maxn];
struct node{
int id;
int dfn;
bool operator <(const node &rhs) const{
return dfn<rhs.dfn;
}
}p[maxn];
int n;
int dfn[maxn];
int head[maxn],cnt=0;
int deg[maxn];
bool vis[maxn];
void add(int u,int v){
e[++cnt].v=v;
e[cnt].next=head[u];
head[u]=cnt;
}
int ct=0;
void dfs(int x){
dfn[x]=++ct;
for (int i=head[x];i;i=e[i].next){
int v=e[i].v;
if(!vis[v]){
vis[v]=1;
dfs(v);
}
}
}
int main(){
scanf("%d",&n);
for (int i=1;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
add(u,v);add(v,u);
deg[u]++;
deg[v]++;
}
if(n == 1){
printf("0\n");return 0;
}
if(n == 2){
printf("1\n");return 0;
}
for (int i=1;i<=n;i++){
if(deg[i] != 1){//找到第一个非叶节点,把其作为树根,求一个dfs序
vis[i] = 1;
dfs(i);
break;
}
}
int tot = 0;
for (int i=1;i<=n;i++){
if(deg[i] == 1){//选出叶子结点
p[++tot].id = i;
p[tot].dfn = dfn[i];
}
}
sort(p+1,p+1+tot);
printf("%d\n",(tot+1)/2);
for (int i=1;i<=(tot+1)/2;i++){
int a=p[i].id,b=p[tot/2+i].id;
printf("%d %d\n",a,b);
}
return 0;
}
水题,不解释
#include
using namespace std;
int main(){
int a1,a2,a3;
int b1,b2,b3;
scanf("%d:%d:%d",&a1,&a2,&a3);
scanf("%d:%d:%d",&b1,&b2,&b3);
int ans;
if(b3<a3){
ans = a3-b3 +(a2-b2)*60+(a1-b1)*3600;
}
else{
ans = b3-a3 +(b2-a2)*60+(b1-a1)*3600;
}
if(ans<0)ans = -ans;
cout<<ans<<endl;
return 0;
}
做法:二维单调队列维护区间的最大值,最后求和即可
#include
#include
#include
using namespace std;
const int N=5005;
typedef long long ll;
ll gcd(ll a,ll b){
return b==0?a:gcd(b,a%b);
}
struct node{
ll pos,x;
}max[N];
ll h1,t1,h2,t2;
int a[N][N],w[N][N];
int main(){
int aa,bb,n;
scanf("%d%d%d",&aa,&bb,&n);
int Max = aa>bb?aa:bb;
for(int i = 1;i<=Max;++i)for(int j = 1;j<=i;++j){
a[j][i] = a[i][j] = i*j/gcd(i,j);
}
for(int j=1;j<=aa;j++){
h1=h2=1; t1=t2=0;
for(int i=1;i<=bb;i++){
if(h1<=t1 && max[h1].pos<i-n+1) h1++;
while(h1<=t1 && max[t1].x<a[j][i]) t1--;
max[++t1].pos=i; max[t1].x=a[j][i];
if(i-n+1>0)
w[j][i-n+1]=max[h1].x;
}
}
for(int j=1;j<=bb-n+1;j++){
h1=h2=1; t1=t2=0;
for(int i=1;i<=aa;i++){
if(h1<=t1 && max[h1].pos<i-n+1) h1++;
while(h1<=t1 && max[t1].x<w[i][j]) t1--;
max[++t1].pos=i; max[t1].x=w[i][j];
if(i-n+1>0)
w[i-n+1][j]=max[h1].x;
}
}
ll ans= 0;
for(int i=1;i<=aa-n+1;i++)
for(int j=1;j<=bb-n+1;j++)
{
ans+=w[i][j];
}
printf("%lld\n",ans);
return 0;
}
做法:bitset维护后缀
#include
using namespace std;
const int N=4e4+7;
const int NN=2e5+7;
bitset<N> bit[N];
int a[NN],b[N],p[N];
int sum;
bool cmp(const int& x,const int& y){
return b[x] < b[y];
}
int main(){
int n,m;
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",b+i);
p[i]=i;
}
sort(p+1,p+m+1,cmp);
sort(b+1,b+m+1);
for(int i=1;i<=m;i++){
bit[i] = bit[i-1];
bit[i].set(m-p[i],1);
}
bitset<N> ans;
for(int i=1;i<m;i++){
int t=upper_bound(b+1,b+m+1,a[i])-b-1;
ans >>=1;
ans.set(m-1,1);
ans &=bit[t];
}
for(int i=m;i<=n;i++){
int t=upper_bound(b+1,b+m+1,a[i])-b-1;
ans >>=1;
ans.set(m-1,1);
ans &=bit[t];
sum +=ans[0];
// cout<
}
printf("%d\n",sum);
return 0;
}
做法:轮换与置换
#include
using namespace std;
const int maxn=1e5+10;
typedef long long ll;
ll n,k;
ll a[maxn],temp[maxn];
ll ans[maxn];
int ct=0;
bool vis[maxn];
vector<int>v;
void gcd(ll a,ll b,ll &d,ll &x,ll &y) {
if(!b) { d=a; x=1; y=0;}
else {gcd(b,a%b,d,y,x); y -= x*(a/b);}
}
ll gcd_inv(ll a,ll n) {
ll d,x,y;
gcd(a,n,d,x,y);
return d == 1 ? (x+n) % n : -1;
}
int main(){
cin>>n>>k;
for (int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
for (int i=1;i<=n;i++){
if(!vis[i]){
v.clear();
for (int j=i;!vis[j];){
v.push_back(j);
vis[j]=1;
j=a[j];
}
ll r = (int)v.size();//环的大小
ll invk = gcd_inv(k % r,r);
// cout<<"invk = "<
for (int j=0;j<r;j++){
temp[j] = v[(j+invk) % r];
}
for (int j=0;j<r;j++){
ans[v[j]] = temp[j];
}
}
}
for (int i=1;i<=n;i++){
if(i!=n) printf("%lld ",ans[i]);
else printf("%lld\n",ans[i]);
}
return 0;
}