补题若干(4)

[https://atcoder.jp/contests/abc418/tasks/abc418_e](数学+容斥)

题意:

给定\(N\)个点的坐标,求能组成多少个梯形

思路:

任意两个直线,若斜率相等,可组成梯形

斜率用分数类计算避免精度丢失以及不存在等情况

这样计算会使得平行四边形(也是梯形)被计算两次

平行四边形的两条对角线线段中点相同

容斥减去

map的const auto&可以避免拷贝依次卡常


struct FRAC{//分数结构体。
	int a,b;//分子和分母。
	FRAC(const int _a=0,const int _b=1):a(_a),b(_b){
		int g=__gcd(a,b);
		a/=g,b/=g,b<0&&(a=-a,b=-b);//保证分母非负,避免比较出现问题。
	}
	bool operator < (const FRAC&B)const{return a*B.b<B.a*b;}//根据分数定义重载小于运算符。
	bool operator == (const FRAC&B)const{return a*B.b==B.a*b;}//同上。
};

map<FRAC,int>mp;
map<pii,int>sp;

int x[2001],y[2001];
void solve(){
    int n;cin>>n;
    rep(i,1,n){
        cin>>x[i]>>y[i];
        for(int j=1;j<=i-1;j++){
            mp[FRAC(y[i]-y[j],x[i]-x[j])]++;
            sp[{y[i]+y[j],x[i]+x[j]}]++;
        }
    }
    int ans=0;
    for(const auto&[a,b]:mp){
        ans+=b*(b-1)/2;
    }
    for(const auto&[a,b]:sp){
        ans-=b*(b-1)/2;
    }
    cout<<ans;
}

[https://atcoder.jp/contests/abc413/tasks/abc413_e](贪心+分治)

题意:

给定一个序列,你只能翻转由2^i组成的区间,求任意次翻转后最小字典序的序列

思路:

发现两两区间互不关联,所以只要让单个区间字典序最小即可,关注单个区间首个数字大小然后交换区间即可:交换=2次翻转2 + 翻转1

int n;
void solve(){
    cin>>n;
    vector<int>a((1ll<<n)+1);
    rep(i,1,(1ll<<n))cin>>a[i];
    for(int len=1;len<=n;len++){
        for(int i=1;i<=(1ll<<n);i+=(1ll<<len)){
            if(a[i]>a[i+(1ll<<len-1)]){
                for(int _=0;_<(1ll<<len-1);_++)swap(a[i+_],a[i+(1ll<<len-1)+_]);
            }
        }
    }
    for(int i=1;i<=(1ll<<n);i++){
        cout<<a[i]<<' ';
    }
    cout<<endl;
}

[https://atcoder.jp/contests/abc403/tasks/abc403_e](tries+打标记)

题意:

给定\(n\)个字符串 , 其中\(x\)个 是字符串集合\(S_1\)的 其他是字符串集合\(S_2\)的 , 求\(S_2\)不以\(S_1\)中的字符串为前缀的字符串个数

思路:

建立字典树

每个结点维护的信息:在\(S_2\)则 此节点的cnt++
对于\(S_1\)中每一个字符串末尾字符所在位置的子树,使其减去贡献

打标记并下传,实现在线查询

int q;
const int M= 1e6 +5;
int tot;
int cnt[M];
int clear[M];
int tries[M][26];


int ans =  0;
int dfs(int p){
    if(clear[p])return 0;
    clear[p]=1;
    int res = 0;
    res += cnt[p];
    for(int i=0;i<26;i++){
        if(tries[p][i]){
            res+=dfs(tries[p][i]);
        }
    }
    return res;
}

void ins1(string s){
    int p=0;
    for(int i=0;i<s.size();i++){
        int k = s[i] - 'a';
        if(!tries[p][k]){
            tries[p][k]=++tot;
        }
        p=tries[p][k];
    }
    if(!clear[p])ans-=dfs(p);
}
void ins2(string s){
    int p=0;
    for(int i=0;i<s.size();i++){
        int k = s[i] - 'a';
        if(!tries[p][k]){
            tries[p][k]=++tot;
        }
        clear[tries[p][k]]=max(clear[tries[p][k]],clear[p]);
        p=tries[p][k];
    }
    cnt[p]++;
    if(!clear[p])ans++;
}
void solve(){
    cin>>q;
    while(q--){
        int _;cin>>_;
        string s;cin>>s;
        if(_==1){ins1(s);}else{ins2(s);}
        cout<<ans<<endl;
    }
}

[https://www.luogu.com.cn/problem/solution/AT_abc402_e](期望+状压DP)

题意:

给定\(n\)个题目,每个题目有取得概率,代价,价值,求当前有x元时,得分的最大期望

思路:

设计DP状态: dp[i][j]表示 :当前还有i元,已经通过了j道题目的状态到结束状态的最大期望得分

转移时:当前题目已通过:重新再交一遍

没通过:概率加权平均值

取max即可

int n,x;
const int M=10;
int s[M],c[M],p[M];
double dp[5005][1024];
//dp[i][j]:当前剩下来的钱是i,已经通过的题目为j 之后的得分期望最大值

//dp[x][0]
void solve(){
    cin>>n>>x;
    rep(i,1,n){
        cin>>s[i]>>c[i]>>p[i];
    }
    int N = (1ll<<n)-1;
    for(int i = 0;i<=x;i++){
        for(int S= 0 ;S<N;S++){
            for(int j=0;j<n;j++){
                if(c[j+1]>i)continue;

                if((1ll<<j)&S){
                    dp[i][S]=max(dp[i][S],dp[i-c[j+1]][S]);
                }else{
                    dp[i][S]=max(dp[i][S],0.01*p[j+1]*(dp[i-c[j+1]][S|(1ll<<j)]+s[j+1])+0.01*(100-p[j+1])*dp[i-c[j+1]][S]);
                }

            }
        }
    }
    cout<<fixed<<setprecision(18)<<dp[x][0];
}

[https://atcoder.jp/contests/abc390/tasks/abc390_e](背包+暴力)

题意:

给定若干个物品,每个物品有维生素含量和卡路里含量
给定卡路里限制\(X\), 求卡路里含量不超过\(X\)时,最少的维生素含量最大值是多少

思路:

求每个维生素种类物品在卡路里限制为\(i\)的维生素含量的最大值\(dp[i]\)

暴力枚举两种维生素的卡路里含量,剩下一个维生素的卡路里含量就确定了

int n,x;
const int M =5005;
int dp1[M],dp2[M],dp3[M];
int v[M],a[M],c[M];
void solve(int *dp,int op){
    rep(i,1,n){
        if(v[i]!=op)continue;
        for(int j=x;j>=c[i];j--){
            dp[j]=max(dp[j],dp[j-c[i]]+a[i]);
        }
    }
}

void solve(){
    cin>>n>>x;
    rep(i,1,n){
        cin>>v[i]>>a[i]>>c[i];
    }
    solve(dp1,1);
    solve(dp2,2);
    solve(dp3,3);
    int ans=0;
    for(int i=1;i<=x;i++){
        for(int j=1;j<=x-i;j++){
            int k = x-i-j;
            ans=max(ans,min({dp1[i],dp2[j],dp3[k]}));
        }
    }
    cout<<ans;
}

[https://atcoder.jp/contests/abc421/tasks/abc421_e](期望+记忆化搜索)

int a[7];
double ans;
map<pair<vector<int>,int>,double>f;

double dfs(vector<int>p,int s){
    if(f.count({p,s})){
        return f[{p,s}];
    }

    if(!s){
        int sum=0,mx=0;

        for(int i=1;i<=6;mx=max(mx,sum),sum=0,i++){
            for(int x:p)if(x==a[i])sum+=x;
        }

        f[{p,s}]=mx;
        return mx;
    }

    int n=5-p.size(),Pow=1;
    while(n--)Pow*=6;
    n=5-p.size();
    double sum = 0;

    for(int st = 0;st<Pow;st++){
        double mx = 0.00;
        int S = st;
        vector<int>add;
        add.clear();
        add.pb(0);
        for(int i=1;i<=n;i++)add.pb(a[S%6+1]),S/=6;
        for(int _=0;_<(1ll<<n);_++){
            vector<int>w = p;
            for(int i=1;i<=n;i++){
                if(_&(1ll<<i-1))w.pb(add[i]);
            }
            mx=max(mx,dfs(w,s-1));
        }
        sum+=mx;
    }

    f[{p,s}]=sum/Pow;return f[{p,s}];
}

void solve(){
    for(int i=1;i<=6;i++)cin>>a[i];
    ans = dfs({},3);
    cout<<fixed<<setprecision(10)<<ans<<endl;
}
posted @ 2025-11-11 11:37  Marinaco  阅读(4)  评论(0)    收藏  举报
//雪花飘落效果