cf Round 613

A.Peter and Snow Blower(计算几何)

给定一个点和一个多边形,求出这个多边形绕这个点旋转一圈后形成的面积。
保证这个点不在多边形内。

画个图能明白 这个图形是一个圆环,那么就是这个点距离多边形边缘最远的距离形成的圆面积减去这个点距离多边形边缘最近的距离形成的圆面积。
我们可以得出距离最远的点一定是多边形的顶点。
而距离最近的点不一定是多边形的顶点,但是在多边形的边上。
我们用勾股定理判断点与每条边形成的三角形的两边角。
如果有一个边角是钝角,则表示距离最近的点是顶点。
如果都是锐角,则表示距离最近的点在底边上。
我们用海伦公式求出三角形的面积,再除以底边*2,那么就得出了这个三角形的高。
此题得解。

# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# include <iostream>
# include <vector>
# include <queue>
# include <stack>
# include <map>
# include <math.h>
# include <algorithm>
using namespace std;
# define lowbit(x) ((x)&(-x))
# define pi acos(-1.0)
# define MAXN 100005
# define eps 1e-5
# define MAXM 1000005
# define MOD 1000000007
# define INF 1000000000
# define mem(a,b) memset(a,b,sizeof(a))
# define FOR(i,a,n) for(int i=a; i<=n; ++i)
# define FO(i,a,n) for(int i=a; i<n; ++i)
# define bug puts("H");
# define lch p<<1,l,mid
# define rch p<<1|1,mid+1,r
# pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
typedef unsigned long long ULL;
int _MAX(int a, int b){return a>b?a:b;}
int _MIN(int a, int b){return a>b?b:a;}
int Scan() {
    int res=0, flag=0;
    char ch;
    if((ch=getchar())==‘-‘) flag=1;
    else if(ch>=‘0‘&&ch<=‘9‘) res=ch-‘0‘;
    while((ch=getchar())>=‘0‘&&ch<=‘9‘)  res=res*10+(ch-‘0‘);
    return flag?-res:res;
}
void Out(int a) {
    if(a<0) {putchar(‘-‘); a=-a;}
    if(a>=10) Out(a/10);
    putchar(a%10+‘0‘);
}

LL a[100005][2];
LL dis(LL x1, LL y1, LL x2, LL y2)
{
    return (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1);
}
int main ()
{
    LL n, px, py, ma=0;
    double mi=1e16;
    scanf("%lld%lld%lld",&n,&px,&py);
    FOR(i,1,n) {
        scanf("%lld%lld",&a[i][0],&a[i][1]);
        LL d = dis(a[i][0],a[i][1],px,py);
        mi=min(mi,(double)d); ma=max(ma,d);
    }
    a[n+1][0]=a[1][0], a[n+1][1]=a[1][1];
    FOR(i,1,n) {
        LL A2=dis(px,py,a[i][0],a[i][1]);
        LL B2=dis(px,py,a[i+1][0],a[i+1][1]);
        LL C2=dis(a[i][0],a[i][1],a[i+1][0],a[i+1][1]);
        double A=sqrt(A2), B=sqrt(B2), C=sqrt(C2);
        if (C2+B2>A2&&C2+A2>B2) {
            double P=(A+B+C)/2;
            double S=sqrt(P*(P-A)*(P-B)*(P-C));
            double H=S/C*2;
            mi=min(mi,H*H);
        }
    }
    printf("%.10lf\n",pi*(ma-mi));
    return 0;
}

B.Skills(贪心+枚举+二分)

给你n个数,可以花费1使得数字+1,最大加到A,最多花费m。最后,n个数里的最小值为min,为A的有k个,给你cm和cf,求force=min*cm+k*cf 的最大值,和n个数操作后的结果。

我们如果要让最小值增加,那它加到和第二小的一样时,就有两个最小值,接下来就要两个一起增加。到后来就要好多个一起增加了。
那么我们可以枚举加到A的有多少个,然后用二分的方法求剩下m元,可以使最小值最大为多少。

#include<bits/stdc++.h>
#define N 100005
#define ll long long
using namespace std;

struct data
{
    ll id,v;
} a[N];

bool cmp(data a,data b)
{
    return a.v<b.v||a.v==b.v&&a.id<b.id;
}

ll n,A,cf,cm,m;
ll L,ans[N],f,ansA,ansL;
ll s[N];

ll findL(ll m,ll R)//还剩多少m,右端点是什么
{
    ll l=0,r=A,ans=0;//二分确定最小值的值

    while(l<=r)
    {

        ll mid=(r+l)>>1;

        //二分确定有多少个比这个值小,然后计算需要的花费
        int p=lower_bound(a+1,a+1+n,(data){0,mid},cmp)-a-1;
        if(p>R)p=R;
        if(p*mid-s[p]<=m)
        {
            ans=mid;
            l=mid+1;
        }
        else
            r=mid-1;
    }
    return ans;
}
int main()
{
    scanf("%lld%lld%lld%lld%lld",&n,&A,&cf,&cm,&m);
    for(int i=1; i<=n; i++)
    {
        scanf("%lld",&a[i].v);
        a[i].id=i;
    }

    sort(a+1,a+n+1,cmp);//先排序再求前缀和
    for(int i=1; i<=n; i++)
        s[i]=s[i-1]+a[i].v;

    for(int i=0; i<=n; i++) //如果有i个设置为A的话
    {

        ll p=A*i-s[n]+s[n-i];//花费
        if(p<=m)
        {
            L=findL(m-p,n-i);//那最小值可以达到多少
            if(cm*L+cf*i>f) //更新答案
            {
                f=cm*L+cf*i;
                ansA=i;//储存有几个变成A
                ansL=L;//储存最小值要达到多少
            }
        }
    }
    printf("%lld\n",f);
    for(int j=1; j<=n; j++)
    {
        if(j>n-ansA)
            ans[a[j].id]=A;
        else if(a[j].v<=ansL)
            ans[a[j].id]=ansL;
        else
            ans[a[j].id]=a[j].v;
    }
    for(int i=1; i<=n; i++)
        printf("%lld ",ans[i]);
    return 0;
}

C.Necklace(构造)

给你n种字符,每种有ai个,构造一个环,要求刨开环之后形成回文串,且种数最多。

显然当ai中有两个奇数,答案为0.
我们可以把这n个字符分成x个部分,且每个部分中每个字符的个数一样。
这样x<=gcd(a1,a2...ai).
我们证明答案一定能取到gcd(a1,a2...ai).
首先如果ai中有一个奇数,我们可以令每个部分都形成一个回文串。
如果ai中没有奇数,我们可以令每个部分与相邻的部分成为一个回文串。可以证明第一个部分
同样可以与最后一个部分成为回文串。
所以答案就是x

# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# include <iostream>
# include <vector>
# include <queue>
# include <stack>
# include <map>
# include <math.h>
# include <algorithm>
using namespace std;
# define lowbit(x) ((x)&(-x))
# define pi acos(-1.0)
# define MAXN 100005
# define eps 1e-5
# define MAXM 1000005
# define MOD 1000000007
# define INF 1000000000
# define mem(a,b) memset(a,b,sizeof(a))
# define FOR(i,a,n) for(int i=a; i<=n; ++i)
# define FO(i,a,n) for(int i=a; i<n; ++i)
# define bug puts("H");
# define lch p<<1,l,mid
# define rch p<<1|1,mid+1,r
# pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
typedef unsigned long long ULL;
int _MAX(int a, int b){return a>b?a:b;}
int _MIN(int a, int b){return a>b?b:a;}
int Scan() {
    int res=0, flag=0;
    char ch;
    if((ch=getchar())==‘-‘) flag=1;
    else if(ch>=‘0‘&&ch<=‘9‘) res=ch-‘0‘;
    while((ch=getchar())>=‘0‘&&ch<=‘9‘)  res=res*10+(ch-‘0‘);
    return flag?-res:res;
}
void Out(int a) {
    if(a<0) {putchar(‘-‘); a=-a;}
    if(a>=10) Out(a/10);
    putchar(a%10+‘0‘);
}

int a[30];

int gcd(int x, int y){y==0?x:gcd(y,x%y);}
int main ()
{
    int n, cnt=0;
    scanf("%d",&n);
    FOR(i,1,n) scanf("%d",a+i), cnt+=a[i]&1;
    int G=a[1];
    FOR(i,2,n) G=gcd(G,a[i]);
    if (n==1) {
        printf("%d\n",a[1]);
        FOR(i,1,a[1]) putchar(‘a‘);
        putchar(‘\n‘);
        return 0;
    }
    if (cnt>=2) {
        puts("0");
        FOR(i,1,n) FOR(j,1,a[i]) putchar(‘a‘+i-1);
        putchar(‘\n‘);
    }
    else if (cnt==1) {
        printf("%d\n",G);
        FOR(k,1,G) {
            FOR(i,1,n) if (a[i]%2==0) FOR(j,1,a[i]/G/2) putchar(‘a‘+i-1);
            FOR(i,1,n) if (a[i]&1) FOR(j,1,a[i]/G) putchar(‘a‘+i-1);
            for (int i=n; i>=1; --i) if (a[i]%2==0) FOR(j,1,a[i]/G/2) putchar(‘a‘+i-1);
        }
    }
    else {
        printf("%d\n",G);
        FOR(k,1,G/2) {
            FOR(i,1,n) FOR(j,1,a[i]/G) putchar(‘a‘+i-1);
            for (int i=n; i>=1; --i) FOR(j,1,a[i]/G) putchar(‘a‘+i-1);
        }
        putchar(‘\n‘);
    }
    return 0;
}

D.Kingdom and its Cities(虚树)

题意:给出n个节点的树,询问q次,每次询问mi个点,问将这mi个点分离开来
至少需要割掉多少个点。
(n<=1e5,sigma(mi)<=1e5)

显然无解的情况是存在两个点相邻。
我们先来考虑每次询问。从树的底层往高层看,
如果一个节点是询问点,那么它的子树中有询问点的就删掉它的子树。
如果一个节点是非询问点,那么它的有询问点的子树超过1个的时候,
就需要把这个节点为根的树给删了。
所以一遍dfs即可。复杂度O(n).对于q个询问,复杂度O(n*q).

因为sigma(mi)<=1e5.
我们把询问点单独拉出来建立一颗虚树。
复杂度O((n+sigma(m))*logn).

# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# include <iostream>
# include <vector>
# include <queue>
# include <stack>
# include <map>
# include <math.h>
# include <algorithm>
using namespace std;
# define lowbit(x) ((x)&(-x))
# define pi acos(-1.0)
# define MAXN 100005
# define eps 1e-5
# define MAXM 500001
# define MOD 1000000007
# define INF 1000000000
# define mem(a,b) memset(a,b,sizeof(a))
# define FOR(i,a,n) for(int i=a; i<=n; ++i)
# define FO(i,a,n) for(int i=a; i<n; ++i)
# define bug puts("H");
typedef long long LL;
typedef unsigned long long ULL;
int _MAX(int a, int b){return a>b?a:b;}
int _MIN(int a, int b){return a>b?b:a;}
int Scan() {
    int res=0, flag=0;
    char ch;
    if((ch=getchar())==‘-‘) flag=1;
    else if(ch>=‘0‘&&ch<=‘9‘) res=ch-‘0‘;
    while((ch=getchar())>=‘0‘&&ch<=‘9‘)  res=res*10+(ch-‘0‘);
    return flag?-res:res;
}
void Out(int a) {
    if(a<0) {putchar(‘-‘); a=-a;}
    if(a>=10) Out(a/10);
    putchar(a%10+‘0‘);
}

struct Edge{int p, next;}edge[MAXN<<1];
int head[MAXN], cnt=1, mark, top, ans;
int bin[20], dep[MAXN], id[MAXN], fa[MAXN][20], h[MAXN], st[MAXN], vis[MAXN];

bool comp(int a, int b){return id[a]<id[b];}
void bin_init(){bin[0]=1; FO(i,1,20) bin[i]=bin[i-1]<<1;}
void add_edge(int u, int v)
{
    if (u==v) return ;
    edge[cnt].p=v; edge[cnt].next=head[u]; head[u]=cnt++;
}
void dfs(int x, int fat)
{
    id[x]=++mark;
    fa[x][0]=fat;
    for (int i=1; bin[i]<=dep[x]; ++i) fa[x][i]=fa[fa[x][i-1]][i-1];
    for (int i=head[x]; i; i=edge[i].next) {
        int v=edge[i].p;
        if (v==fat) continue;
        dep[v]=dep[x]+1;
        dfs(v,x);
    }
}
int dp_dfs(int x)
{
    if (vis[x]) {
        for (int i=head[x]; i; i=edge[i].next) {
            int v=edge[i].p;
            if (dp_dfs(v)) ans++;
        }
        head[x]=vis[x]=0;
        return 1;
    }
    else {
        int tot=0;
        for (int i=head[x]; i; i=edge[i].next) {
            int v=edge[i].p;
            tot+=dp_dfs(v);
        }
        head[x]=vis[x]=0;
        if (tot>1) {ans++; return 0;}
        else return tot;
    }
}
int lca(int x, int y)
{
    if (dep[x]<dep[y]) swap(x,y);
    int t=dep[x]-dep[y];
    for (int i=0; bin[i]<=t; ++i) if (bin[i]&t) x=fa[x][i];
    if (x==y) return x;
    for (int i=19; i>=0; --i) if (fa[x][i]!=fa[y][i]) x=fa[x][i], y=fa[y][i];
    return fa[x][0];
}
void sol()
{
    int m=Scan();
    cnt=1; top=0, ans=0;
    FOR(i,1,m) h[i]=Scan(), vis[h[i]]=1;
    sort(h+1,h+m+1,comp);
    FOR(i,2,m) if (vis[fa[h[i]][0]]) {
        puts("-1");
        FOR(i,1,m) vis[h[i]]=0;
        return ;
    }
    st[++top]=1;
    int P=h[1]==1?2:1;
    FOR(i,P,m) {
        int f=lca(h[i],st[top]);
        while (dep[f]<dep[st[top-1]]) add_edge(st[top-1],st[top]), top--;
        add_edge(f,st[top--]);
        if (f!=st[top]) st[++top]=f;
        st[++top]=h[i];
     }
     while (top>1) add_edge(st[top-1],st[top]), top--;
     dp_dfs(1);
     printf("%d\n",ans);
}
int main ()
{
    bin_init();
    int n, q, u, v;
    n=Scan();
    FO(i,1,n) u=Scan(), v=Scan(), add_edge(u,v), add_edge(v,u);
    dfs(1,0);
    q=Scan(); mem(head,0);
    while (q--) sol();
    return 0;
}

E.Puzzle Lover(待填坑)

时间: 2024-10-14 16:52:16

cf Round 613的相关文章

CF Round 594

CF Round 594(Div1) (A~D)简要题解 开学基本打不了cf了啊.. A Ivan the Fool and the Probability Theory 对于 $ 1 \times n $ 的情况,稍微推一推式子发现是斐波那契数列的两倍(因为第一个位置可以是0可以是1,就是两倍了,否则是一倍). 考虑第一行,第一行有两种情况: 如果第一行是 01010... 交错的,那么 0 开头可以看成一种颜色,1 开头可以看成一种颜色.然后就成了一个竖着的 $ 1 \times n $ 的

CF Round #629

CF Round #629 A.数学 给定a,b,现在问你最小让a加多少使得a能被b整除,可以为0 即算(b-(a%b))%b B.数学 给定n和k 问以n-2个a和2个b组成的串中,以字典序升序排列,问第k个是几 这个有点类似康托展开,这个简化了很多 首先考虑第一个b,它处在从左往右数第p位,那么无论第二个b怎么放,它最大是(p-1)*p/2 所以只要找到第一个b为u,第二个b从u-1开始,每往后移一位就小一,找k即可 C.数学 给定n和x x是一串开头必为2,由0,1,2组成的字符串,一共有

cf Round#273 Div.2

题目链接,点击一下 Round#273 Div.2 ================== problem A Initial Bet ================== 很简单,打了两三场的cf第一次在10分钟内过题 判平均数,且注意b为正 1 #include<iostream> 2 using namespace std; 3 int main() 4 { 5 int res = 0,n; 6 for(int i = 0; i < 5; i++) 7 { 8 cin>>

【codeforces】【比赛题解】#915 Educational CF Round 36

虽然最近打了很多场CF,也涨了很多分,但是好久没写CF的题解了. 前几次刚刚紫名的CF,太伤感情了,一下子就掉下来了,不懂你们Div.1. 珂学的那场我只做了第一题--悲伤. 这次的Educational Round打的还可以,虽然吧没有涨分(因为我是紫色的啊). 做了前4题,后面3题也比较简单,陆续也做完了. 所以心情好,来写一篇题解! [A]花园 题意: 长度为\(k\)的线段,用若干个长度为\(a_i\)的线段,正好覆盖.(\(a_i|k\)) 给定\(n\)个\(a_i\),求出最小的\

【codeforces】【比赛题解】#854 CF Round #433 (Div.2)

cf一如既往挺丧 看丧题点我! [A]分数 Petya是数学迷,特别是有关于分数的数学.最近他学了所谓一个分数被叫做"真分数"当且仅当其分子小于分母,而一个分数被叫做"最简分数"当且仅当其分子分母互质.在闲暇时间,Petya在用计算器研究:如何把最简真分数转换为小数等问题.有一天他不小心把除号(÷)按成了加号(+),导致他得到了分子与分母的和.Petya想要得到他原来的分数,但他很快发现这不是唯一的.所以现在他想要知道最大的最简真分数使得其分子与分母的和为n. 输入

【codeforces】【比赛题解】#849 CF Round #431 (Div.2)

cf的比赛越来越有难度了--至少我做起来是这样. 先看看题目吧:点我. 这次比赛是北京时间21:35开始的,算是比较良心. [A]奇数与结束 "奇数从哪里开始,又在哪里结束?梦想从何处起航,它们又是否会破灭呢?" 给定一个长度为n的序列.确定能不能将序列分成奇数个长度为奇数的非空字串,而且这其中每个子串以奇数开头,以奇数结尾.可以只分成一个(1也是奇数). 输入 第一行一个正整数n,表示序列长度. 第二行n个整数,表示序列中的元素. 输出 输出"Yes"或"

CF Round #631 题解

\(Codeforces\) \(Round\) \(631\) A.Dreamoon and Ranking Collection 题目大意: \(n\)轮比赛,每轮比赛排名已经给出,还可以进行额外的\(m\)场比赛 问:所有比赛进行完后,最多可以收集到从\(1\)开始的多少个连续名次 题解: 用一个数组统计一下排名的出现情况,然后扫一遍添加\(m\)个缺失名次即可 代码: #include<iostream> #include<cstdio> #include<cstdl

【解题报告】CF Round #320 (Div. 2)

Raising Bacteria 题意:盒子里面的细菌每天会数量翻倍,你可以在任意一天放任意多的细菌,最后要使得某天盒子里面的细菌数量等于x,求至少要放多少个细菌 思路:显然,翻倍即为二进制左移一位,那么放入一个细菌,到第二天就变成2个二进制下即为1->10对于任意二进制数 如:1001110,只需要在第一天放1个,第4.5.6天各放一个,再等一天,就可以了.所以答案显然是x在二进制下1的个数. Finding Team Member 题意:2n个人,每两个人组合的队伍有aij的力量.每个人都希

CF round #292 解题报告

A题: 给出一个坐标(a,b),和走的步数,问有没有可能从(0,0)走这么多步刚好到达(a,b). 水题,结果还是wa了一次,没有考虑到a<0或者b<0的情况. 1 #include<cstdio> 2 int main() 3 { 4 int a,b,s; 5 while(scanf("%d%d%d",&a,&b,&s)!=EOF){ 6 if(a<0) 7 a=-a; 8 if(b<0) 9 b=-b; 10 if(a+b