链接:https://ac.nowcoder.com/acm/contest/911/A
来源:牛客网

A Good 的集合

题目描述
平面上给 n(3≤n≤1000) 个点,保证不存在 3 点共线,保证这些点两两不重合,对于一个点集 S ,如果从 S 中任意选出三个不同的点,构成的三角形重心都不是整点(横坐标,纵坐标都是整数的点,称为整点),那么这个点集是 good 的,输出最大的 good 的点集大小。(注:所有点数小于等于 2 的点集都是 good 的)。

解:由重心坐标((x1+x2+x3)/3,(y1+y2+y3)/3)可得点的类型只能分为9种:(0-3,0-3)。
并且同一种点最多有两个,因此统计点的种类数并DFS求解。

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define FI first
#define SE second
#define PII pair<int,int>
#define endl '\n'
#define PB push_back
const double INF = 1e17+7;
const int N = 1e5 + 7;
int n,k;
PII a[9]={PII(0,0),PII(0,1),PII(0,2),PII(1,0),PII(1,1),PII(1,2),PII(2,0),PII(2,1),PII(2,2)};
map<PII,int>mp;
int ans;
int check(int x){
    for(int i=0;i<9;i++){
        if((x>>i)&1)
        for(int j=i+1;j<9;j++){
            if((x>>j)&1)
            for(int c=j+1;c<9;c++){
                if((x>>c)&1){
                    if((a[i].FI+a[j].FI+a[c].FI)%3==0&&(a[i].SE+a[j].SE+a[c].SE)%3==0)return 0;
                }
            }
        }
    }
    return 1;
}
void dfs(int x,int y,int z){
    if(z==9)return;
    if(check(x|(1<<z))&&mp[a[z]]){
        int cnt=min(mp[a[z]],2);
        ans=max(ans,y+cnt);
        dfs(x|(1<<z),y+cnt,z+1);
    }
    dfs(x,y,z+1);
}
int main()
{
    for(int i=0;i<9;i++){
        mp[a[i]]=0;
    }
    cin>>n;
    int x,y;
    for(int i=1;i<=n;i++){
        scanf("%d%d",&x,&y);
        mp[PII(x%3,y%3)]++;
    }
    dfs(0,0,0);
    cout<<ans;
    return 0;
}

B 狂赌之渊

链接:https://ac.nowcoder.com/acm/contest/911/B
来源:牛客网

题目描述
有 n 堆石头,第 i 堆石头有 ai 个石子,两人轮流操作,每次操作先选择一堆石头,再从这堆石头中取走一个石子,如果此次操作取完了被选择的这堆石头的最后一个石子,操作者得一分。当所有石子被取走时,游戏结束。输出先手最大得分。

思路:偶数堆先取必输,如果我当前取偶数堆,那对手再取一次该堆就能使局势保持不变,因此只能先取奇数堆,判断一下谁会先将奇数堆取完谁就输,并且要么全胜要么全败。

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define FI first
#define SE second
#define PII pair<int,int>
#define endl '\n'
#define PB push_back
const int INF = 1e9+7;
const int N = 1e5 + 7;
int n,m;
int main()
{
    cin>>n;
    int cnt=0;
    int x;
    for(int i=1;i<=n;i++){
        scanf("%d",&x);
        if(x%2)cnt++;
    }
    if(cnt%2)cout<<n;
    else cout<<0;
    return 0;
}

D O(n!)

链接:https://ac.nowcoder.com/acm/contest/911/D
来源:牛客网

题目描述
有 n件商品,第 i件商品价格为 a[i],购买后,其它所有未购买的商品价格乘上 p[i],现在要买下所有商品,输出最小耗费。

思路:将相邻物品按对对方造成的优惠排序,每一次交换都不会影响到其他物品的价格。

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define FI first
#define SE second
#define PII pair<int,int>
#define endl '\n'
#define PB push_back
const double INF = 1e17+7;
const int N = 1e5 + 7;
int n,m;
struct s{
    double x,y,z;
}a[N];
bool cmp(s p,s q){
    return p.x*(1-q.y)<(1-p.y)*q.x;
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++){
        scanf("%lf%lf",&a[i].x,&a[i].y);
    }
    double ans=INF;
    sort(a+1,a+1+n,cmp);
    double k=1;
    ans=0;
    for(int i=1;i<=n;i++){
        ans+=a[i].x*k;
        k*=a[i].y;
    }
    printf("%.6lf\n",ans);
    return 0;
}

E.斐波那契串

链接:https://ac.nowcoder.com/acm/contest/911/E
来源:牛客网

题目描述
str1,str2为给定的字符串,定义 F[1] = str1, F[2] = str2,F[i]=F[i-1]+F[i-2],其中 “+” 表示字符串拼接,字符串由小写英文字母组成。多组查询,每组查询输入 x,y,输出F[x]的第 y 位,x,y≤1018(下标从 1 开始)。

思路:y不超过1e18,则存前log1e18 的长度即可,然后递归处理,如果x很大就二分减小范围。

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define FI first
#define SE second
#define PII pair<int,int>
#define endl '\n'
#define PB push_back
const LL INF = 1e18,mod=1e9+7;
const int N = 1e5 + 7;
int n,k;
char a[N],b[N];
LL s[N];
int main()
{
    scanf("%s%s",a,b);
    int l=strlen(a),ll=strlen(b);
    s[1]=l,s[2]=ll;
    s[3]=l+ll;
    int cnt=3;
    while(s[cnt]<INF){
        cnt++;
        s[cnt]=s[cnt-1]+s[cnt-2];
    }
    int q;
    cin>>q;
    LL x;
    LL y;
    while(q--){
        scanf("%lld%lld",&x,&y);
        if(y>=s[3])
        x=lower_bound(s+1,s+1+cnt,y)-s;
        while(x>2){
            if(y>s[x-1]){
                y-=s[x-1];
                x-=2;
            }
            else{
                x-=1;
            }
        }
        if(x==2){
            printf("%c\n",b[y-1]);
        }
        else printf("%c\n",a[y-1]);
    }
    return 0;
}

F.无交集的圆

题目描述:
Y轴上有许多圆,所有圆的圆心位于Y轴,求有多少对圆是没有交集的(不包含、不相交、不相切)。

思路:将与y轴的上交点排序,然后对于每个圆与y轴的下交点二分查找有多少上交点在其下面

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define FI first
#define SE second
#define PII pair<int,int>
#define endl '\n'
#define PB push_back
const double INF = 1e17+7;
const int N = 1e5 + 7;
int n,m;
int a[N],b[N];
int main()
{
    cin>>n;
    double x,y;
    for(int i=1;i<=n;i++){
        scanf("%lf%lf",&x,&y);
        a[i]=x-y,b[i]=x+y;
    }
    sort(a+1,a+1+n);
    LL ans=0;
    for(int i=1;i<=n;i++){
        int k=upper_bound(a+1,a+1+n,b[i])-a;
        ans+=(n-k+1);
    }
    cout<<ans;
    return 0;
}

G-最长递增长度

题目描述
给定一个长度为n的整数序列S,求这个序列中最长的严格递增子序列的长度。

最长上升子序列模板题

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define FI first
#define SE second
#define PII pair<int,int>
#define endl '\n'
#define PB push_back
const int INF = 1e9+7;
const int N = 1e6 + 7;
int n,m;
int a[N];
int s[N];
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)s[i]=INF;
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        *lower_bound(s+1,s+1+n,a[i])=a[i];
    }
    int ans=lower_bound(s+1,s+1+n,INF)-s-1;
    cout<<ans;
    return 0;
}

H 虚无的后缀

链接:https://ac.nowcoder.com/acm/contest/911/H
来源:牛客网

题目描述
给出 n 个数字,第 i 个数字为 a[i],我们从中选出 k 个数字,使得乘积后缀 0 的个数最多。

思路:对于每个数字求出整除2和5的次数,然后以5为空间2为价格进行二维背包

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define FI first
#define SE second
#define PII pair<int,int>
#define endl '\n'
#define PB push_back
const int INF = 1e17+7,mod=1e9+7;
const int N = 1e5 + 7;
int n,k;
int s[201][5202];
int q[201][5202];
int main()
{
    cin>>n>>k;
    LL x;
    q[0][0]=1;
    for(int i=1;i<=n;i++){
        scanf("%lld",&x);
        int t=0,f=0;
        while(x%5==0){
            f++;
            x/=5;
        }
        while(x%2==0){
            t++;
            x/=2;
        }
        for(int j=k;j>=1;j--){
            for(int c=n*26;c>=f;c--){
                if(q[j-1][c-f]){
                    q[j][c]=1;
                    s[j][c]=max(s[j][c],s[j-1][c-f]+t);
                }
            }
        }
    }
    int ans=0;
    for(int i=0;i<=n*26;i++){
        ans=max(ans,min(i,s[k][i]));
    }
    cout<<ans;
    return 0;
}

I 大吉大利

链接:https://ac.nowcoder.com/acm/contest/911/I
来源:牛客网

题目描述
有 n 个人,编号为 1 ~ n,第 i 个人有 a[i] 枚金币,若第一个人金币数大于 0,则可以选择一个i(2≤i≤n) 然后,弃置 1 枚金币,让第 i 个人弃置 b[i] 枚金币,若第 i 个人金币数少于 b[i] 则弃置所有金币。现需要让第 1 个⼈人弃置最少的⾦金金币,成为唯⼀的金币数最多的人。

思路:二分答案检查是否合理

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define FI first
#define SE second
#define PII pair<int,int>
#define endl '\n'
#define PB push_back
const int INF = 1e9+7;
const int N = 1e5 + 7;
int n,m;
int a[N];
int b[N];
int check(int x){
    int re=0;
    int num=a[1]-x-1;
    for(int i=2;i<=n;i++){
        if(a[i]>=num){
            int k=(a[i]-num)/b[i];
            if((a[i]-num)%b[i])k++;
            re+=k;
        }
    }
    return re<=x;
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    for(int i=2;i<=n;i++){
        scanf("%d",&b[i]);
    }
    int ans=a[1]+1;
    int l=0,r=a[1];
    while(l<=r){
        int mid=l+r>>1;
        if(check(mid)){
            ans=min(ans,mid);
            r=mid-1;
        }
        else l=mid+1;
    }
    if(ans>a[1])cout<<-1;
    else cout<<ans;
    return 0;
}

J 异或的路径
链接:https://ac.nowcoder.com/acm/contest/911/J
来源:牛客网

题目描述
给一棵 n 个点的树,1 号节点为根,边有边权,令 f(u,v) 表示 u 节点到 v 节点,路径上边权异或值。求 ∑i=1n∑j=1nf(i,j),结果对 1000000007 取模。

思路:跑一遍dfs求出每个点到根的路径异或和,然后按二进制位数个数算贡献

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define FI first
#define SE second
#define PII pair<int,int>
#define endl '\n'
#define PB push_back
const int INF = 1e17+7,mod=1e9+7;
const int N = 1e5 + 7;
int n,k;
int a[N];
int cct[62];
int d[N];
vector<PII>v[N];
void dfs(int x,int y){
    d[x]=y;
    int z=y;
    int cnt=0;
    while(z){
        if(z&1)cct[cnt]++;
        cnt++;
        z>>=1;
    }
    for(int i=0;i<v[x].size();i++){
        dfs(v[x][i].FI,y^v[x][i].SE);
    }
}
int main()
{
    cin>>n;
    int x,y;
    for(int i=2;i<=n;i++){
        scanf("%d%d",&x,&y);
        v[x].PB(PII(i,y));
    }
    dfs(1,0);
    LL ans=0;
    for(int i=1;i<=n;i++){
        for(int j=0;j<20;j++){
            if((d[i]>>j)&1){
                ans+=1ll*(1ll<<j)%mod*(n-cct[j]);
            }
            else ans+=1ll*(1ll<<j)%mod*cct[j];
            ans%=mod;
        }
    }
    cout<<ans%mod;
    return 0;
}