Northwestern European Regional Contest 2014 Gym

Gym 101482C Cent Savings

简单的dp

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define inf64 0x3f3f3f3f3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=2200;
ll dp[maxn][22],sum[maxn];

int main(){
    int n,m;
    scanf("%d%d",&n,&m);m++;
    for(int i=1;i<=n;i++){
        scanf("%lld",&sum[i]);
        sum[i]+=sum[i-1];
    }
    memset(dp,inf64,sizeof(dp));
    dp[0][0]=0;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=min(i,m);j++){
            for(int k=0;k<i;k++){
                ll val=sum[i]-sum[k];
                val=(val+5)/10*10;
                dp[i][j]=min(dp[i][j],dp[k][j-1]+val);
            }
        }
    }
    ll ans=inf64;
    for(int i=1;i<=m;i++) ans=min(ans,dp[n][i]);
    printf("%lld
",ans);
    return 0;
}
/*
5 1
13 21 55 60 42
5 2
1 1 1 1 1
 */

Gym 101482D Digi Comp II
拓扑,注意细节

#include <bits/stdc++.h>
using namespace std;
const int maxn=5e5+10;
typedef long long ll;
ll num[maxn],n,m;
int cur[maxn],L[maxn],R[maxn],in[maxn];
void tp(){
    queue<int>que;
    while(!que.empty()) que.pop();
    for(int i=1;i<=m;i++){
        if(in[i]==0) que.push(i);
    }
    while(!que.empty()){
        int u = que.front();que.pop();
        int lc=L[u],rc=R[u];
        if(cur[u]) num[lc]+=num[u]/2,num[rc]+=(num[u]+1)/2;
        else num[lc]+=(num[u]+1)/2,num[rc]+=num[u]/2;
        in[lc]--;
        if(in[lc]==0) que.push(lc);
        in[rc]--;
        if(in[rc]==0) que.push(rc);
    }
}
int main(){
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=m;i++){
        char s[10];
        scanf("%s%d%d",s,&L[i],&R[i]);
        in[L[i]]++,in[R[i]]++;
        if(s[0]=='L') cur[i]=0;
        else cur[i]=1;
    }
    num[1]=n;
    tp();
    for(int i=1;i<=m;i++){
        if(num[i]&1) cur[i]^=1;
        if(cur[i]==0) printf("L");
        else printf("R");
    }
    printf("
");
    return 0;
}

E - Euclidean TSP Gym - 101482E

这个题目不是我写的,好像只要看清楚题目,就会了?三分

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <stack>
#include <bitset>
#include <vector>
#include <map>
#include <math.h>
#include <string>
#include <cstring>
#define fir first
#define sec second
using namespace std;
typedef long long ll;
const int maxn = 1e4+7;

double n,p,s,v;
double k1,k2,res;
double m = sqrt(2);

double val(double x) {
    return k1*pow(k2,x)+res*(1+1/x);
}

int main() {
    cin>>n>>p>>s>>v;
    k1 = n/p/1e9;
    k2 = pow(log(n)/log(2),m);
    res = s/v;
    double l = 0 ,r = 1e10;

    for(int i=0;i<100;i++) {
        double len = (r-l)/3.0;
        double lmid = len+l;
        double rmid = lmid+len;
        if(val(lmid) > val(rmid)) l = lmid;
        else r = rmid;
    }
    printf("%.7f %.7f
",val(l),l);
    return 0;
}
/*
l, r = start, end
    epsilon = 1e-6
    # 我们自定义的终止条件是区间长度小于1d-6
    while l + epsilon < r:
        margin = (r - l) / 3.0
        m1 = l + margin
        m2 = m1 + margin
        if f(m1) <= f(m2):
            r = m2
        else:
            l = m1
*/

Gym 101482F Finding Lines

随机数,比较奇葩,很少碰到这样的题目

#include<iostream>
#include<cstdlib>
#include<ctime>
#define N 100005
using namespace std;
typedef long long ll;
namespace random {
    typedef unsigned ui;
    typedef long long ll;
    typedef unsigned long long ull;
    ui X, Y, Z, W;
    void start() {
        srand ( (ui) time (NULL) );
        X = rand(), Y = X ^ rand(), Z = Y ^ rand();
    }
    ui RNG61() {
        X = X ^ (X << 11);
        X = X ^ (X >> 4);
        X = X ^ (X << 5);
        X = X ^ (X >> 14);
        W = X ^ Y ^ Z;
        X = Y;
        Y = Z;
        Z = W;
        return Z;
    }
    int Randint (int mod) {return RNG61() % mod + 1;}
    ll Randll(ll mod) {return ((ull)RNG61() << 32 | RNG61()) % mod + 1;}
    double Randdouble(int l, int r) {
        if(l == r) return l;
        if(l > r) swap(l, r);
        double ret = RNG61() % (r - l) + l;
        double tmp = RNG61();
        while(tmp > 1) tmp /= 10;
        ret += tmp;
        return ret;
    }
}
using namespace random;
struct point{
    ll x,y;
}a[N];
ll n,p,ans;

ll check(ll first,ll second){
    ll sum=2;
    ll x1=a[first].x-a[second].x;
    ll y1=a[first].y-a[second].y;
    for(int i=0;i<n;++i){
        if(i==first||i==second)continue;
        ll x2=a[i].x-a[second].x;
        ll y2=a[i].y-a[second].y;
        if(x1*y2-x2*y1==0)sum++;
    }
    if(sum*100-p*n>=0)return 1;
    return 0;
}
int main(void){
    start();
    while(cin>>n>>p){
        for(ll i=0;i<n;++i)
            cin>>a[i].x>>a[i].y;
        if(n<=2){
            cout<<"possible
";
            continue;
        }
        ans=0;
        for(ll t=0;t<100;++t){
            ll first=Randint(n-1),second=Randint(n-1);
            if(first==second)continue;
            ans+=check(first,second);
//           if(ans) printf("first=%lld second =%lld
",first,second);
        }
        if(ans)cout<<"possible
";
        else cout<<"impossible
";
    }
}

Gym 101482G Gathering 三分+切比雪夫距离

题目大意:

给你n个点,给定每一个点的坐标,自己定一个中心城市,要求每一个点到这个中心城市的曼哈顿距离要小于等于d,求这个中心城市到每一个城市的曼哈顿距离和最小。

题解:

写这个题目之前要学习一下 切比雪夫距离,学习博客->切比雪夫距离

把切比雪夫距离 ((x,y)) 转化成曼哈顿距离 ((x+y,x-y))

把曼哈顿距离 ((x,y)) 转化为切比雪夫距离 ((frac{x+y}{2},frac{x-y}{2}))

其次就是要知道如果没有这个d的限制,则最小的应该是x的中位数和y的中位数的那个点。

  • 首先通过曼哈顿距离转化成切比雪夫距离,然后求出上下左右四个边界。

  • 然后因为没有d的限制最小的是x的中位数和y的中位数,所以要三分这个x的距离,当确定这个x之后,怎么求y呢?

    • 第一种方法,三分求y,因为y也是中位数是一个峰值,但是这样会T在37组。
    • 第二种方法,直接判断此时的x对应的y的最小值和最大值,如果中位数在 (ymin)(ymax) 之间,则直接取中位数,如果 (ymax < ymid) 则取(ymax) ,如果 (ymin>ymid) 则取 (ymin)
  • 最后就是求答案,注意三分的写法。
    (1) 这个 其实很简单,但是我傻逼了,想了好久。。。

其实就是这个xx要转化成切比雪夫后要满足四个边界要求

(xx,y)曼哈顿 转化成切比雪夫(xx+y,xx-y)

l<xx+y<r 和 down<xx-y<up 求出这个y的范围

#include <bits/stdc++.h>
#define inf64 0x3f3f3f3f3f3f3f3f
using namespace std;
const int maxn=1e5+10;
typedef long long ll;
ll x[maxn],y[maxn],gx[maxn],gy[maxn],midy,n,d;
ll down,up,lc,rc;
ll solve(ll xx){
    ll yup=min(xx-down,rc-xx);//这里看解释(1)
    ll ydn=max(xx-up,lc-xx);
    if(yup<ydn) return inf64;
    ll dy=0,ans=0;
    if(midy<=yup&&midy>=ydn) dy=midy;
    else if(midy>yup) dy=yup;
    else dy=ydn;
    for(int i=1;i<=n;i++) ans+=abs(x[i]-xx)+abs(y[i]-dy);
    return ans;
}

int main(){
    scanf("%lld",&n);
    down = -inf64,up = inf64;
    lc = -inf64,rc = inf64;
    for(int i=1;i<=n;i++)scanf("%lld%lld",&x[i],&y[i]);
    scanf("%lld",&d);
    for(int i=1;i<=n;i++){
        down=max(down,x[i]-y[i]-d);
        up=min(up,x[i]-y[i]+d);
        lc=max(lc,x[i]+y[i]-d);
        rc=min(rc,x[i]+y[i]+d);
    }
    if(down>up||lc>rc) {
        printf("impossible
");
        return 0;
    }
    sort(y+1,y+1+n);midy=y[(n+1)/2];
    ll L=(lc+down)/2,R=(rc+up)/2,ans=inf64;
    while(L<R-2){
        ll l = L + (R-L)/3,ans1=solve(l);
        ll r = R - (R-L)/3,ans2=solve(r);
        if(ans1>ans2) L=l,ans=min(ans,ans2);
        else R=r,ans=min(ans,ans1);
    }
    for(;L<=R;L++) ans=min(ans,solve(L));
    printf("%lld
",ans);
    return 0;
}

Gym 101482H Hyacinth

简单的图论题

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define inf64 0x3f3f3f3f3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=1e4+10;
int lc[maxn],rc[maxn];	
struct node{
    int v,nxt;
    node(int v=0,int nxt=0):v(v),nxt(nxt){}
}e[maxn*2];
int head[maxn],cnt,now;
void add(int u,int v){
    e[++cnt]=node(v,head[u]);
    head[u]=cnt;
    e[++cnt]=node(u,head[v]);
    head[v]=cnt;
}
void dfs(int u,int pre){
    int res=0;
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].v;
        if(v==pre) continue;
        res++;
        if(res==1){
            lc[v]=rc[u];
            rc[v]=++now;
        }
        else {
            lc[v]=lc[u];
            rc[v]=++now;
        }
        dfs(v,u);
    }
}
int main(){
    int n;
    cnt=0,now=2;
    scanf("%d",&n);
    for(int i=1;i<n;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        add(u,v);
    }
    lc[1]=1,rc[1]=2;
    dfs(1,0);
    if(n==2){
        printf("1 2
");
        printf("1 2
");
    }
    else {
        for(int i=1;i<=n;i++){
            printf("%d %d
",lc[i],rc[i]);
        }
    }
    return 0;
}

Gym 101482I Indoorienteering 双向搜索

题目大意:

给你一个数n,和一个(n*n)的方阵,对于方阵中的 (d[i][j]) 表示 (i)(j) 之间的最短距离。

求遍历n个点,最后回到起点,其他点只走一次的,求距离和是否能达到L。

题解:

就是一个双向搜索,如果不会双向搜索可以看看这个题目->送礼物

因为我是要判断是否可以达到距离和为L,而不是求经过所有的点的最小距离或者说是最大距离或者说是方案数,所以不可以用状压(dp) ,必须要进行暴力的搜索来求这个距离和。

为什么这个可以用双向搜索呢,因为我已知这个距离和了,所以要充分利用这个条件。

  • 首先我要把这个划分成两个集合,两个集合大小尽量相等,但是怎么划分这两个集合呢?

    首先我们要明白这个集合是不能随意划分的,不能说前 (n/2) 为第一个集合,后面的数自动成为第二个集合。为什么不能呢,假设,n=6,最后满足条件的是 1-4-3-2-5-6 ,但是我把 1 2 3 放到了一个集合,意味着1一定要和2 或者3 直接相连,但是呢这个并不满足条件。

  • 所以这个集合的划分应该暴力来求解。

  • 其次,对于第一个集合,我们是求出这个集合的所有的可能解,然后存下来,这样的话,是不是这个集合的起点和终点必须确定,因为如果不确定,则第一个集合的起点要和第二个集合的终点连边第一个集合的终点要和第二个集合的起点连边,这样的话,这两个距离就无法确定,那么也就不能二分来求答案了。

  • 对于第一个集合的起点是很好确定的,可以任意选一个值,因为你想想啊,每一个点都必须经过,而又是一个圈,所以第一个集合的起点就可以任意定下来,终点就直接枚举即可。

(bug) 一定要静下心来找!!!

#include <bits/stdc++.h>
#define inf64 0x3f3f3f3f3f3f3f3f
using namespace std;
const int maxn=1e5+10;
typedef long long ll;
ll w[20][20],a[20],b[20],vis[20],n,L,g[maxn];
int cnta,cntb,num=0;

void dfs1(int u,int t,ll sum,int now){
//	printf("u=%d t=%d sum=%lld now=%d
",u,t,sum,now);
    if(sum>L) return ;
    if(now==cnta&&u==t){
        g[++num]=sum;
        return ;
    }
    if(u==t) return ;
    
	for(int i=2;i<=cnta;i++){
    	int v=a[i];
        if(vis[v]) continue;
        vis[v]=1;
        dfs1(v,t,sum+w[u][v],now+1);
        vis[v]=0;
    }
}
int f=0;
void dfs2(int u,ll sum,int now){
//	printf("u=%d sum=%lld now=%d
",u,sum,now);
    if(sum>L) return ;
    if(now==cntb){
        sum+=w[u][1];
        if(sum>L) return ;
        int t=lower_bound(g+1,g+1+num,L-sum)-g;
        if(g[t]+sum==L) f=1;
//        printf("b[%d]=%d sum=%lld t=%d g=%d f=%d
",u,b[u],sum,t,g[t],f);
        return ;
    }
    for(int i=1;i<=cntb;i++){
    	int v=b[i];
        if(vis[v]) continue;
        vis[v]=1;
        dfs2(v,sum+w[u][v],now+1);
        vis[v]=0;
    }
}

bool judge(int t){
    memset(vis,0, sizeof(vis));
    vis[1]=1,num=0;
    dfs1(1,t,0,1);
    
    sort(g+1,g+1+num);
	num=unique(g+1,g+1+num)-g-1;
    
//	for(int i=1;i<=num;i++) printf("g[%d]=%lld
",i,g[i]);
    
	memset(vis,0, sizeof(vis));
    dfs2(t,0,0);
//    printf("xxx f=%d
",f);
    return f;
}

bool solve(){
    for(int i=2;i<=cnta;i++) if(judge(a[i])) return true;
    return false;
}

int main(){
	f = 0;
    scanf("%lld%lld",&n,&L);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            scanf("%lld",&w[i][j]);
        }
    }
    if(n<=3){
    	ll sum=0;
    	if(n==2) sum=2*w[1][2];
    	else sum=w[1][2]+w[2][3]+w[1][3];
    	if(sum==L) printf("possible
");
    	else printf("impossible
");
    	return 0;
	}
    for(int s=0;s<(1<<n);s++){
        cnta=0,cntb=0;
        for(int j=1;j<=n;j++){
            int tmp=1<<(j-1);
            if(tmp&s) a[++cnta]=j;
            else b[++cntb]=j;
        }
        if(cnta==n/2&&a[1]==1){
            if(solve()){
                printf("possible
");
                return 0;
            }
        }
    }
    printf("impossible
");
    return 0;
}

Gym 101482J
签到题

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define inf64 0x3f3f3f3f3f3f3f3f
using namespace std;
const int maxn=3e6+10;
map<string,int>mp;

int main(){
    int n,ans=0;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        string s;
        cin>>s;
        mp[s]++;
    }
    for(int i=1;i<=n;i++){
        string s;
        cin>>s;
        if(mp[s]) ans++,mp[s]--;
    }
    printf("%d
",ans);
    return 0;
}

Gym 101482K
这个把所有的离散化一下然后暴力求每一个位置开始的解

#include <bits/stdc++.h>
#define inf64 0x3f3f3f3f3f3f3f3f
using namespace std;
const int maxn=2e3+10;
typedef long long ll;
int cur[maxn],num[maxn],a[maxn],v[maxn];
ll val[maxn];
set<ll>st;
ll gcd(ll a,ll b){
	return b==0?a:gcd(b,a%b);
}

int main(){
    int n,s,t;
    scanf("%d%d%d",&n,&s,&t);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]),v[i]=a[i];
    sort(v+1,v+1+n);
    int len = unique(v+1,v+1+n) - v - 1;
    for(int i=1;i<=n;i++){
        int w=lower_bound(v+1,v+1+len,a[i])-v;
        num[w]++;
    }
    for(int i=1;i<=len;i++){
        st.clear();
        st.insert(inf64);
        for(int j=1;j<=len;j++){
            st.insert(v[j]);
            cur[j]=num[j];
        }
        int sum=n,now=v[i];
        while(sum){
            ll pos = *st.lower_bound(now);
            if(pos>=inf64) val[i]+=(0-now+s)%s,now=0;
            else {
                val[i]+=pos-now,sum--;
                int w=lower_bound(v+1,v+1+len,pos)-v;cur[w]--;
                if(cur[w]==0) st.erase(pos);
            	now=(pos+t)%s;
    			val[i]+=t;
            }
        }
    }
    ll sum=0,mins=inf64,maxs=0;
    mins=min(mins,val[1]);
    ll x=(v[1]-v[len]+s-1)%s;
    maxs=max(maxs,x+val[1]);
    sum+=(val[1]+val[1]+x)*(x+1)/2;
    for(int i=2;i<=len;i++){
    	x = (v[i]-v[i-1]+s-1)%s;
    	maxs=max(maxs,x+val[i]);
    	mins=min(mins,val[i]);
    	sum+=(val[i]+val[i]+x)*(x+1)/2;
	}
	ll g=gcd(sum,s);
	sum/=g,s/=g;
	printf("%lld
%lld
%lld/%d
",mins,maxs,sum,s);
    return 0;
}
原文地址:https://www.cnblogs.com/EchoZQN/p/12807079.html