Helvetic Coding Contest 2019 online mirror (teams allowed, unrated)

http://codeforces.com/contest/1184

A1

找一对整数,使x^x+2xy+x+1=r

变换成一个分式,保证整除

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include <map>
#define fo(i,l,r) for(int i = l;i <= r;i++)
#define ll long long
using namespace std;
const int maxn = 300050;
const ll mod = 1e9+7;
inline ll read(){
    ll x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9'){
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9'){
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}
ll r;
int main(){
    r=read();
    for(ll i = 1;i <= 1000000;i++){
        if(i*i>r)break;
        ll t = r-i*i-i-1;
        if(t<=0)continue;
        if(t%(i+i)==0){
            cout<<i<<" "<<t/(i+i);
            return 0;
        }
    }
    cout<<"NO";
    return 0;
}
View Code

A2

给定一个二进制串,对于整数k来说,若存在另一个二进制串x,时x与x右移k位异或的结果等于这个二进制串,k就是合法的,求合法的k的数量。

先考虑x,第一个位确定了,后面1+k,1+2k...的位也确定了,最后会回到第一位,这时需要与之前假定的第一位一致。于是这就形成了一个循环。循环长度为lcm(k,n)/k=n/gcd(k,n)。

对k,按gcd(k,n),进行归纳求解,将所有k映射到gcd(k,n),然后求出gcd(k,n)的答案,只需要遍历所有循环的位置,再查看是否合法。

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include <map>
#define fo(i,l,r) for(int i = l;i <= r;i++)
#define ll long long
using namespace std;
const int maxn = 200050;
const ll mod = 1e9+7;
inline ll read(){
    ll x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9'){
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9'){
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}
int n;
int a[maxn];
char s[maxn];
bool vis[maxn];
bool can[maxn];
int gcd(int a,int b){
    return b==0?a:gcd(b,a%b);
}
int main(){
    n=read();
    scanf("%s",s+1);
    fo(i,1,n){
        a[i] = s[i] - '0';
    }
    int ans = 0,tot = 0;
    fo(i,1,n){
        int g = gcd(i,n);
        if(vis[g]){
            ans += can[g];
        }else{
            vis[g]=true;
            bool ok=false;
            fo(j,1,g){
                ok=true;
                tot=0;
                for(int k = j;k <= n;k += g){
                    tot += a[k];
                }
                if(tot%2){
                    ok=false;
                    break;
                }
            }
            if(ok) can[g]=true;
            ans += can[g];
        }
    }
    cout<<ans;
    return 0;
}
View Code

B1

舰队攻打敌军,只能攻打防御力不大于它攻击力的,敌军掉落的金币不等,问每个船能打多少钱

排序即可

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include <map>
#define fo(i,l,r) for(int i = l;i <= r;i++)
#define ll long long
using namespace std;
const int maxn = 200050;
const ll mod = 1e9+7;
inline ll read(){
    ll x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9'){
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9'){
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}
int s,b;
struct dat{
    int pos;
    int val;
    friend bool operator < (dat a,dat b){
        return a.val < b.val;
    }
}shp[maxn],ene[maxn];
ll gold[maxn];
int main(){
    s=read();
    b=read();
    fo(i,1,s){
        shp[i].pos=i;
        shp[i].val=read();
    }
    fo(i,1,b){
        ene[i].val=read();
        ene[i].pos=read();
    }
    sort(shp+1,shp+1+s);
    sort(ene+1,ene+1+b);
    int pos=0;
    ll ans = 0;
    fo(i,1,s){
        while(pos<b&&ene[pos+1].val<=shp[i].val){
            pos++;
            ans += ene[pos].pos;
        }
        gold[shp[i].pos]=ans;
    }
    fo(i,1,s){
        printf("%I64d ",gold[i]);
    }
    return 0;
}
View Code

B2

敌军在一个图上攻打舰队,每个敌军只能打防御力不大于他的船,并且两者距离不大于他的燃油量。每个敌军负责打一个人,掠夺k金币。

我军可以花h金币建造假船,一定会被一个敌军攻击,且不损失金币。求损失最少的策略。

因为金币数量是固定的,容易证明要么全用假船吸引,要么一个假船都不放。

先跑多源最短路,然后匹配即可。

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include <map>
#define fo(i,l,r) for(int i = l;i <= r;i++)
#define ll long long
using namespace std;
const int maxn = 200050;
const ll mod = 1e9+7;
inline ll read(){
    ll x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9'){
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9'){
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}
int n,m;
int dis[105][105];
int s,b;
ll kk,hh;
struct ship{
    int x;
    ll f;
    ll a;
}ships[1050];
struct ene{
    int x;
    ll d;
}enes[1050];
int uN,vN;
int g[1050][1050];
int linker[1050];
int used[1050];
bool dfs(int u){
    for(int v = 0;v < vN;v++){
        if(g[u][v] && !used[v]){
            used[v] = true;
            if(linker[v]==-1||dfs(linker[v])){
                linker[v]=u;
                return true;
            }
        }
    }
    return false;
}
int hungary(){
    int res = 0;
    memset(linker,-1, sizeof(linker));
    for(int u = 0;u < uN;u++){
        memset(used,false, sizeof(used));
        if(dfs(u))res++;
    }
    return res;
}
int main(){
    n=read();
    m=read();
    int u,v;
    fo(i,1,n){
        fo(j,1,n){
            dis[i][j]=1e7;
        }
        dis[i][i]=0;
    }
    fo(i,1,m){
        u=read();
        v=read();
        dis[u][v] = 1;
    }
    fo(k,1,n){
        fo(i,1,n){
            fo(j,1,n){
                if(k==i||k==j||i==j)continue;
                dis[i][j] = min(dis[i][j],dis[i][k]+dis[k][j]);
            }
        }
    }
    s=read();b=read();kk=read();hh=read();
    fo(i,1,s){
        ships[i].x=read();
        ships[i].a=read();
        ships[i].f=read();
    }
    fo(i,1,b){
        enes[i].x=read();
        enes[i].d=read();
    }
    uN=s;
    vN=b;
    fo(i,1,s){
        fo(j,1,b){
            if(ships[i].a >= enes[j].d && dis[ships[i].x][ships[j].x] <= ships[i].f) g[i-1][j-1]=1;
        }
    }
    ll ans = min((ll)s*hh,kk*hungary());
    cout<<ans;
    return 0;
}
View Code

C1

给若干个在长方形边上的点和一个不在边上的点,找出那个长方形

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include <map>
#define fo(i,l,r) for(int i = l;i <= r;i++)
#define ll long long
using namespace std;
const int maxn = 55;
const ll mod = 1e9+7;
inline ll read(){
    ll x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9'){
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9'){
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}
int n;
int x[maxn],y[maxn];
bool check(int x1,int x2,int y1,int y2){
    int cnt = 0,t=0;
    bool debug=false;
    if(x1==19&&x2==45&&y1==1&&y2==27)debug=true;
    fo(i,1,n){
        if(x[i]<x1||x[i]>x2||y[i]<y1||y[i]>y2){
            cnt++;
            t=i;
        }else if(x[i]!=x1&&x[i]!=x2&&y[i]!=y1&&y[i]!=y2){
            cnt++;
            t=i;
        }
        if(cnt>1)return false;
    }
    if(cnt == 0) return false;
    cout<<x[t]<<" "<<y[t];
    return true;
}
int main(){
    n=read();
    n = n*4+1;
    fo(i,1,n){
        x[i]=read();
        y[i]=read();
    }
    fo(i,0,50){
        fo(j,i,50){
            fo(k,0,50){
                fo(l,k,50){
                    if(check(i,j,k,l)) return 0;
                }
            }
        }
    }
    return 0;
}
View Code

D1

一个长度n的线段和一个特殊点,每次插入或者切掉头或尾一段,每次询问特殊点的位置。

维护即可。

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include <map>
#define fo(i,l,r) for(int i = l;i <= r;i++)
#define ll long long
using namespace std;
const int maxn = 305;
const ll mod = 1e9+7;
inline ll read(){
    ll x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9'){
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9'){
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}
int n,k,m,t;
int main(){
    n=read();k=read();
    m=read();t=read();
    int opt,v;
    fo(i,1,t){
        opt=read();
        v=read();
        if(opt==1){
            n++;
            if(v<=k)k++;
        }else{
            if(k > v){
                n-=v;
                k-=v;
            }else{
                n=v;
            }
        }
        cout<<n<<" "<<k<<endl;
    }
    return 0;
}
View Code

E1

给一个图,求出最小生成树,问如果第一条边可能在最小生成树里,其边权最多是多大

看看什么时候这条边对应的两个点处于同一个集合中。

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include <map>
#define fo(i,l,r) for(int i = l;i <= r;i++)
#define ll long long
using namespace std;
const int maxn = 100050;
const ll mod = 1e9+7;
inline ll read(){
    ll x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9'){
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9'){
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}
int n,m;
int f[maxn];
int findf(int x){
    return f[x]==x?x:f[x]=findf(f[x]);
}
struct edge{
    int u;
    int v;
    ll w;
    friend bool operator < (edge a,edge b){
        return a.w < b.w;
    }
}e[maxn*10];
int main(){
    n=read();m=read();
    fo(i,1,m){
        e[i].u=read();
        e[i].v=read();
        e[i].w=read();
    }
    fo(i,1,n){
        f[i]=i;
    }
    int aa = e[1].u,bb=e[1].v;
    sort(e+1,e+1+m);
    fo(i,1,m){
        int u=e[i].u;
        int v=e[i].v;
        int fu=findf(u),fv=findf(v);
        if(fu==fv) continue;
        if(e[i].u==aa&&e[i].v==bb)continue;
        f[fu]=fv;
        if(findf(aa)==findf(bb)){
 
            cout<<e[i].w;
            return 0;
        }
    }
    cout<<1000000000;
    return 0;
}
View Code

E2

与上一个问题类似,但是这次要求除了最小生成树的边之外所有边的答案

先求最小生成树,两个点之间加一条边,则形成一个环,由这条边和两者的树上最短路径的边组成,用lca求最短路径上的边的最大边权即可。

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include <map>
#define fo(i,l,r) for(int i = l;i <= r;i++)
#define ll long long
using namespace std;
const int maxn = 100050;
const ll mod = 1e9+7;
inline ll read(){
    ll x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9'){
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9'){
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}
int n,m;
int f[maxn];
int findf(int x){
    return f[x]==x?x:f[x]=findf(f[x]);
}
struct edge{
    int u;
    int v;
    ll w;
    int id;
    friend bool operator < (edge a,edge b){
        return a.w < b.w;
    }
}e[maxn*10];
bool chs[maxn*10];
bool cmp(edge a,edge b){
    return a.id < b.id;
}
int dep[maxn];
int fa[maxn][25];
ll fw[maxn][25];
struct te{
    int v;
    ll w;
}now,nxt;
vector<te> g[maxn];
void dfs(int x,int p){
    int k = 0;   
    while(fa[x][k]&&fa[fa[x][k]][k]){
        fa[x][k+1] = fa[fa[x][k]][k];
        fw[x][k+1] = max(fw[x][k],fw[fa[x][k]][k]);
        k++;
    }
    int sz = g[x].size();
    int v=0;
    fo(i,0,sz-1){
        v=g[x][i].v;
        if(v==p)continue;
        fa[v][0] = x;
        fw[v][0] = g[x][i].w;
        dep[v] = dep[x] + 1;
        dfs(v,x);
    }
}
ll getans(int u,int v){
    if(dep[u]<dep[v]) swap(u,v);
    ll mx = 0;
    int k = 0,dif=dep[u]-dep[v];
    int ru=u,rv=v;
    while(dif){
        if(dif&1){
            mx = max(fw[u][k],mx);
            u = fa[u][k];
        }
        dif >>= 1;
        k++;
    }
    if(u==v)return mx;
    k = 0;
    while(k >= 0){
        if(fa[u][k] != fa[v][k]){
            mx = max(mx,fw[u][k]);
            mx = max(mx,fw[v][k]);
            u = fa[u][k];
            v = fa[v][k];
            k++;
        }else{
            k--;
        }
    }
    mx = max(mx,fw[u][0]);
    mx = max(mx,fw[v][0]);
    return mx;
}
int main(){
    n=read();m=read();
    fo(i,1,m){
        e[i].u=read();
        e[i].v=read();
        e[i].w=read();
        e[i].id=i;
    }
    fo(i,1,n){
        f[i]=i;
    }
    sort(e+1,e+1+m);
    fo(i,1,m){
        int u=e[i].u;
        int v=e[i].v;
        int fu=findf(u),fv=findf(v);
        if(fu==fv) continue;
        f[fu]=fv;
        chs[e[i].id]=true;
        now.w=e[i].w;
        now.v=v;
        g[u].push_back(now);
        now.v=u;
        g[v].push_back(now);
    }
    dfs(1,0);
    sort(e+1,e+1+m,cmp);
    fo(i,1,m){
        if(chs[i])continue;
        printf("%I64d\n",getans(e[i].u,e[i].v));
    }
    return 0;
}
View Code

 

posted @ 2019-07-10 17:31  ACforever  阅读(240)  评论(0编辑  收藏  举报