HDU 2018 Multi-University Training Contest 10 题解(H G I L J)

Problem H. Pow

水题,jave的BigIntrger过一波

import java.util.*;
import java.math.*;
class Main{
    public static void main(String argv[]){
        Scanner s = new Scanner(System.in);
        int T=s.nextInt();
        while(T-- >0){
            System.out.println(BigInteger.ONE.shiftLeft(s.nextInt()));
        }
    }
}


Problem G. Cyclic

打表找规律, a [ i ] = ( i 3 ) a [ i 1 ] + ( 2 a [ i 2 ] + a [ i 3 ] ) ( i 2 )

D a[100090];
const int mod= 998244353;
void init(){
    a[1]=0,a[2]=0,a[3]=1,a[4]=1,a[5]=8,a[6]=36;
    for(int i=7;i<=100000;i++)a[i]=((i-3)*a[i-1]%mod+(2*a[i-2]%mod+a[i-3])%mod*(i-2)%mod)%mod;
}

int main(){
    init();
    int t=read();
    int n;
    while(t--){
        int n=read();
        printf("%lld\n",a[n]);
    }
}

Problem I. Count

题意:

i = 1 n j = 1 i 1 ( g c d ( i + j , i j ) )

解析:

我开始是知道辗转相减的,也用了,不过化解成了 g c d ( j , i j ) 做了半天。。。其实化成 g c d ( 2 i , i j ) 就直接做出来了

首先 g c d ( 2 i , i j ) = g c d ( 2 i , i + j ) ,且当 i > 2 时, ϕ ( i ) 为偶数(欧拉函数),那么就是说, i 时的答案为 ϕ ( 2 i ) / 2 (不知道欧拉函数的我就没办法了)

但是题目n的范围为2e7, 2*n是4e7, 什么概念, 线性筛会T,所以要处理一下

当i为奇数时, ϕ ( 2 i ) = ϕ ( i ) ;
当i为偶数时, ϕ ( 2 i ) = 2 ϕ ( i ) ;(如果a是素数且n是a倍数 , 有 ϕ ( n a ) = ϕ ( n ) a )

所以我们只需要处理2e7的欧拉函数即可

代码:

#define D long long
#define F double
#define mmm(a,b) memset(a,b,sizeof(a))
D read(){ D ans=0; char last=' ',ch=getchar();
while(ch<'0' || ch>'9')last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;
}
const int N=20000000;
const F pi=acos(-1);
const D mod=1e9+7;
const F _e=2.718281828459045;

const int MAXN = 2e7+5;
bool flag[MAXN];
D phi[MAXN];
D p[MAXN];
D cnt ;

void Get_phi(D m){
    cnt = 0;
    memset(flag, true, sizeof(flag));
    phi[1] = 1ll;
    for(D i=2ll; i<=m; i++)   {
        if(flag[i]) {
            p[++cnt] = i;
            phi[i] = i-1ll;//性质2
        }
        for(D j=1; j<=cnt&&i*p[j]<=m; j++){
            flag[i*p[j]] = false;
            if(i%p[j] == 0){
                phi[i*p[j]] = p[j] * phi[i];//性质3
                break;
            }
            else phi[i*p[j]] = (p[j]-1ll) * phi[i];//性质1
        }
    }
}

D sum[MAXN];

int main(){
    D m=20000000;
    Get_phi(m);
    for(int i=1;i<=m;i++)
        if(i%2)sum[i]=sum[i-1]+phi[i]/2;
        else sum[i]=sum[i-1]+phi[i];
    int t=read();
    while(t--){
            int n;
        scanf("%d",&n);
        printf("%lld\n",sum[n]);
    }
}

Problem L.Videos

队友做的h,就直接上代码吧

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=400000;
const int maxm=1000000;
const int inf=0x3f3f3f3f;
int dis[maxn];
int vis[maxn],pre[maxn];
int head[maxn],cnt,viss[maxn],visss[maxm];
int n,m,sp,tp,k,W;
ll ans=0;
struct node{
    int to,cap,cost,next;
}e[maxm];
void add(int from,int to,int cap,int cost){
    e[cnt].to=to; e[cnt].cap=cap;
    e[cnt].cost=cost; e[cnt].next=head[from];
    head[from]=cnt++;

    e[cnt].to=from; e[cnt].cap=0;
    e[cnt].cost=-cost; e[cnt].next=head[to];
    head[to]=cnt++;
}
bool spfa(int s,int t,int &flow,int &cost){
    queue<int> q;
    memset(dis,inf,sizeof(dis));
    memset(vis,0,sizeof(vis));
    memset(pre,-1,sizeof(pre));
    dis[s]=0;  q.push(s);
    vis[s]=1;
    int d=inf;
    while(!q.empty()){
        int u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=head[u];~i;i=e[i].next){
            int v=e[i].to;
            if(e[i].cap>0&&dis[v]>dis[u]+e[i].cost){
                dis[v]=dis[u]+e[i].cost;
                pre[v]=i;
                if(!vis[v]){
                    vis[v]=1;
                    q.push(v);
                }
            }
        }
    }
    if(dis[t]==inf){
        return false;
    }
    for(int i=pre[t];~i;i=pre[e[i^1].to]){
        d=min(d,e[i].cap);
    }
    for(int i=pre[t];~i;i=pre[e[i^1].to]){
        e[i].cap-=d;
        e[i^1].cap+=d;
        cost+=e[i].cost*d;
    }
    flow+=d;
    return true;
}
int mcmf(int s,int t){
    int flow=0,cost=0;
    while(spfa(s,t,flow,cost)){
        //cout<<flow<<" "<<cost<<endl;
    }
    return cost;
}
int gainp(int m,int n){
    return 200+(m-1)*200+n;
}
int gainaim(int x){
    if(x<=200||x>50000) return 0;

    x-=200;
    x=x/200+1;

    if(!viss[x]) return x;
    else return 0;
}
struct vid{
    int st,en,val,ty,id;
    bool operator <(const vid &a) const {
        return en<a.en;
    }
}vs[205];
vector<vid> vide[201];
void dfs(int x,int fa,int flag){
    visss[x]=1;
    int tflag=flag;
    if(x==tp) return ;
    for(int i=head[x];~i;i=e[i].next){
        if(e[i].cap==0){
            int aim=gainaim(e[i].to);
            if(aim) {
                if(vs[aim].ty!=flag)
                ans+=vs[aim].val,viss[aim]=1;
                else ans-=W,ans+=vs[aim].val;
                flag=vs[aim].ty;
                viss[aim]=1;
            }
            if(e[i].to==fa||visss[e[i].to]) continue;
            dfs(e[i].to,x,flag);
            flag=tflag;
        }
    }
}
int main(){
    int t;
    cin>>t;
    while(t--){
        memset(visss,0,sizeof(visss));
        memset(viss,0,sizeof(viss));
        memset(head,-1,sizeof(head));
        ans=0;
        scanf("%d%d%d%d",&n,&m,&k,&W);
        for(int i=1;i<=n;i++){
            vide[i].clear();
        }
        sp=0;tp=50001;
        for(int i=1;i<=k;i++){
            add(sp,i,1,0);
        }
        for(int i=1;i<=m;i++){
            scanf("%d%d%d%d",&vs[i].st,&vs[i].en,&vs[i].val,&vs[i].ty);
            vs[i].id=i;
            vide[vs[i].st].push_back(vs[i]);
        }
        for(int i=1;i<=k;i++){
            for(int j=1;j<=m;j++){
                add(i,gainp(j,vs[j].st),1,0);
            }
        }
        for(int i=1;i<=m;i++){
            int now=vs[i].en;
            for(int j=now;j<=n;j++){
                for(int k=0;k<vide[j].size();k++){
                    vid x=vide[j][k];
                    if(x.ty==vs[i].ty){
                        add(gainp(i,vs[i].en),gainp(x.id,x.st),1,W);
                    }
                    else {
                        add(gainp(i,vs[i].en),gainp(x.id,x.st),1,0);
                    }
                }
            }
            add(gainp(i,vs[i].st),gainp(i,vs[i].en),1,-vs[i].val);
            if(vs[i].en!=n) add(gainp(i,vs[i].en),gainp(i,n),1,0);
            add(gainp(i,n),tp,1,0);
        }
        cout<<-mcmf(sp,tp)<<endl;
        //dfs(sp,-1,-1);
        //printf("%lld\n",ans);
    }
    return 0;
}

Problem J. CSGO

题意:

有n件主武器和m件副武器,所有武器有一个价值S,已经K种属性,你选择一件主和一件副,得到的价值为 S 1 + S 2 + i = 1 k | K 1 i K 2 i | ,也就是S要大,两件武器属性差要大

解析:

对于一件武器i,它的K种属性对最后答案的贡献只有 2 k 种(0000,0001,0010…),0表示比另一个小所以要减,1表示比另一个大所以要加

用w[x]表示所有主武器的K种属性在状态为x(转为二进制)时的最大贡献

例子:K种属性为2,3,4,x为5(101)时,贡献为2-3+4=3

在维护好w[]后,对于副武器中的一个i的K种属性,也枚举 2 k 个状态,然后和之前主武器中的相反状态(每位异或)相加(当然为了方便不修改状态,主武器0减1加,副武器0加1减),维护答案取一个最大值就行了

有人会问了,加减不是由属性的大小关系决定的吗?

其实是没关系的,假设主武器3 6 4, 副武器4 5 5
最优的主武器状态肯定是010,答案为(-3+4)+(6-5)+(-4+5)=3
但是如果你用111去测呢?答案为(3-4)+(6-5)+(4-5)=-1

就是说,这种不合法的情况虽然也会加入计算,但是绝对不会是最优的情况,所以不会有影响

#include<bits/stdc++.h>
using namespace std;
#define D long long
D read(){ D ans=0; char last=' ',ch=getchar();
while(ch<'0' || ch>'9')last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;
}

int main(){
    int t=read();
    while(t--){
        D n=read(),m=read(),k=read();
        D w[40];
        memset(w,0,sizeof(w));
        for(D i=1;i<=n;i++){//0110 -> -++-
            D s=read();
            D ar[6];for(D j=1;j<=k;j++)ar[j]=read();
            for(D j=0;j<(1<<k);j++){
                D ans=s;
                for(D h=1;h<=k;h++){
                    if(j&(1<<(h-1)))ans+=ar[h];
                    else ans-=ar[h];
                }
                w[j]=max(w[j],ans);
            }
        }
        D A=0;
        for(D i=1;i<=m;i++){//0110 -> -++-
            D s=read();
            D ar[6];for(D j=1;j<=k;j++)ar[j]=read();
            for(D j=0;j<(1<<k);j++){
                D ans=s;
                for(D h=1;h<=k;h++){
                    if(j&(1<<(h-1)))ans-=ar[h];
                    else ans+=ar[h];
                }
                A=max(A,ans+w[j]);
            }
        }
        printf("%lld\n",A);
    }
}

猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/81949115