Social Infrastructure Information Systems Division, Hitachi Programming Contest 2020

传送门

A - Hitachi String

#include <bits/stdc++.h>
#define ll long long
using namespace std;
char s[15];
int main() {
    //freopen("in.txt","r",stdin);
    scanf("%s",s);
    int n=strlen(s);
    if(n&1) printf("No\n");
    else {
        bool f=true;
        for(int i=0;i<n;i+=2) {
            if(s[i]!='h'||s[i+1]!='i') f=false;
        }
        printf("%s\n",f?"Yes":"No");
    }
    return 0;
}
A.cpp

B - Nice Shopping

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+5;
int a[N],b[N];
int main() {
    //freopen("in.txt","r",stdin);
    int n,m,q,mi=1e9,ans=1e9;
    scanf("%d%d%d",&n,&m,&q);
    for(int i=1;i<=n;i++) {
        scanf("%d",&a[i]);
        mi=min(mi,a[i]);
    }
    for(int i=1;i<=m;i++) {
        scanf("%d",&b[i]);
        ans=min(ans,mi+b[i]);
    }
    for(int i=0,x,y,c;i<q;i++) {
        scanf("%d%d%d",&x,&y,&c);
        ans=min(ans,a[x]+b[y]-c);
    }
    printf("%d\n",ans);
    return 0;
}
B.cpp

C - ThREE

题意:给一个有N个节点的无根树,要求将1~N分别给N个结点当作权值,且满足任意一对距离为3的节点权值的和或积是3的倍数,若不存在输出-1。

数据范围:$2 \leq N \leq 2 \times 10^{5}$

题解:可以发现只有两个模3为1的数和两个模3为2的数的情况,不满足和或积是3的倍数。以1为根,求出每个点的深度,距离为3的两个节点深度差为3或1,因此可以根据深度奇偶性来分配模为1和模为2的数。

这里记深度为奇数的个数为x,深度为偶数的个数为y。

1.$x\geq \frac{N}{3} \ and \ y\geq \frac{N}{3}$

将模为1的数依次分配给深度为奇数的点,将模为2的数依次分配给偶数深度的点,剩余的数随便分配。

2.$x \leq \frac{N}{3}$

将模为0的数以此分配给深度为奇数的点,其它数分配给深度为偶数的点。

3.$y \leq \frac{N}{3}$

将模为0的数以此分配给深度为偶数的点,其它数分配给深度为奇数的点。

以上包含所有情况,因此不存在的情况没有。

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N=2e5+5;
vector<int> G[N];
int dep[N],ans[N];
void dfs(int u,int fa) {
    for(auto v:G[u]) {
        if(v==fa) continue;
        dep[v]=dep[u]+1;
        dfs(v,u);
    }
}
int main() {
    //freopen("in.txt","r",stdin);
    int n;
    scanf("%d",&n);
    for(int i=1,u,v;i<n;i++) {
        scanf("%d%d",&u,&v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    dfs(1,-1);
    vector<int> A,B,V[3],Ans[2];
    for(int i=1;i<=n;i++) {
        if(dep[i]&1) A.push_back(i);
        else B.push_back(i);
    }
    for(int i=1;i<=n;i++) {
        V[i%3].push_back(i);
    }
    if(A.size()>=V[1].size()&&B.size()>=V[2].size()) {
        for(auto it:V[1]) Ans[0].push_back(it);
        for(auto it:V[2]) Ans[1].push_back(it);
        int t=A.size()-V[1].size();
        for(int i=0;i<t;i++) Ans[0].push_back(V[0][i]);
        for(int i=t;i<V[0].size();i++) Ans[1].push_back(V[0][i]);
    }
    else if(A.size()<V[1].size()) {
        for(int i=0;i<A.size();i++) Ans[0].push_back(V[0][i]);
        for(int i=A.size();i<V[0].size();i++) Ans[1].push_back(V[0][i]);
        for(auto it:V[1]) Ans[1].push_back(it);
        for(auto it:V[2]) Ans[1].push_back(it);
    }
    else {
        for(int i=0;i<B.size();i++) Ans[1].push_back(V[0][i]);
        for(int i=B.size();i<V[0].size();i++) Ans[0].push_back(V[0][i]);
        for(auto it:V[1]) Ans[0].push_back(it);
        for(auto it:V[2]) Ans[0].push_back(it);
    }
    for(int i=0;i<A.size();i++) {
        ans[A[i]]=Ans[0][i];
    }
    for(int i=0;i<B.size();i++) {
        ans[B[i]]=Ans[1][i];
    }
    for(int i=1;i<=n;i++) {
        printf("%d%c",ans[i],i==n?'\n':' ');
    }
    return 0;
}
C.cpp

 D - Manga Market

题意:有N个商店,当到达第i个商店的时间为t,则在该商店排队ai*t+bi时间单位,问T个时间单位最多能到多少个商店买东西(一个商店只能买一次)。

数据范围:$1 \leq N \leq 2\times 10^{5},0 \leq ai,bi,T \leq 10^{9}$

题解:考虑当前时刻去哪个商店更优,设t时刻准备去第i个商店比第j个商店更优,可以得出:

$1+a_{i}\times(t+1)+b_{i}+1+a_{j}\times(t+1+a_{i}\times(t+1)+b_{i}+1)+b_{j} \leq1+a_{j}\times(t+1)+b_{j}+1+a_{i}\times(t+1+a_{j}\times(t+1)+b_{j}+1)+b_{i}\Leftrightarrow \frac{a_{j}}{b_{j}+1} \geq \frac{a_{i}}{b_{i}+1}$

将N个商店按$\frac{a}{b+1}$降序,然后进行动态规划,按最暴力的需要O(N^2)。

1.当a=0时,显然按b从小到大取。

2.当a!=0时,可以发现时间是指数级上升的,显然能去的商店不超过30个。

定义f[i][j]代表1~i个商店里去了j个商店后的最少时间,然后二分判断把a=0的商店加进去,更新答案即可。

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N=2e5+5;
struct P {
    int a,b;
    bool operator <(const P &t) const {
        return a*(t.b+1)>t.a*(b+1);
    }
}p[N];
ll pre[N];
int n,t,cnt=0,tot=0;
int cal() {
    ll f[35];
    for(int i=0;i<35;i++) f[i]=(i?1e9:0);
    for(int i=0;i<cnt;i++) {
        for(int j=30;j>=0;j--) {
            if(f[j]==1e9) continue;
            f[j+1]=min(f[j+1],(f[j]+1)*(p[i].a+1)+p[i].b);
            if(f[j+1]>t) f[j+1]=1e9;
        }
    }
    int ans=0;
    for(int i=0;i<32;i++) {
        if(f[i]!=1e9) {
            int x=t-f[i];
            int l=1,r=tot,y=-1;
            while(l<=r) {
                int mid=(l+r)>>1;
                if(pre[mid]<=x) y=mid,l=mid+1;
                else r=mid-1;
            }
            if(y!=-1) ans=max(ans,i+y);
            else ans=max(ans,i);
        }
    }
    return ans;
}
int main() {
    //freopen("in.txt","r",stdin);
    scanf("%d%d",&n,&t);
    for(int i=0,a,b;i<n;i++) {
        scanf("%d%d",&a,&b);
        if(a==0) pre[++tot]=b;
        else p[cnt++]={a,b};
    }
    sort(p,p+cnt),sort(pre+1,pre+tot+1);
    for(int i=1;i<=tot;i++) pre[i]+=pre[i-1]+1;
    printf("%d\n",cal());
    return 0;
}
D.cpp

 

posted @ 2020-03-09 21:27  zdragon  阅读(356)  评论(0编辑  收藏  举报