Codeforces gym 2014 Nordic Collegiate Programming Contest(最初版,有过题再更新)

2014.10.25 训练,和一个队友做cf上的gym的比赛,过了6题。

感觉还可以,有几道水题没有卡住,一道模拟,一道贪心,一道高精度+推公式

剩下的,一道kmp(非裸题),一道dfs搜索,一道数学期望

还有一道G题看了没做,问了学长,是一个环连着多个树,然后dp.. 没弄出来。感觉这个姿势很神奇

G I J 已经被我亮星了,改天过了,再更新本博文

已过题目:ACDEFHK

待过题目:GIJ

感觉过不了的题目(=。=!):BF



 


这题还是很简单的。

每个点要不然有登机口,要不然没有。

对于一个联通图,如果一个点确定了是否有登机口,那么这个联通图中的所有点都可以确定是否有登机口。

对于每个联通图,dfs搜索,假设起点有和没有两种情况来搜。

要分情况讨论,注意impossible成立的条件。

这里细讲太过于冗杂,就不陈述了。代码如下:

(dfs不太好写)

//Hello. I'm Peter.
#include<cstdio>
#include<iostream>
#include<sstream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<cctype>
#include<ctime>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double ld;
#define peter cout<<"i am peter"<<endl
#define input freopen("data.txt","r",stdin)
#define randin srand((unsigned int)time(NULL))
#define INT (0x3f3f3f3f)*2
#define LL (0x3f3f3f3f3f3f3f3f)*2
#define gsize(a) (int)a.size()
#define len(a) (int)strlen(a)
#define slen(s) (int)s.length()
#define pb(a) push_back(a)
#define clr(a) memset(a,0,sizeof(a))
#define clr_minus1(a) memset(a,-1,sizeof(a))
#define clr_INT(a) memset(a,INT,sizeof(a))
#define clr_true(a) memset(a,true,sizeof(a))
#define clr_false(a) memset(a,false,sizeof(a))
#define clr_queue(q) while(!q.empty()) q.pop()
#define clr_stack(s) while(!s.empty()) s.pop()
#define rep(i, a, b) for (int i = a; i < b; i++)
#define dep(i, a, b) for (int i = a; i > b; i--)
#define repin(i, a, b) for (int i = a; i <= b; i++)
#define depin(i, a, b) for (int i = a; i >= b; i--)
#define pi acos(-1.0)
#define eps 1e-6
#define MOD 1000000007
#define MAXN 200100
#define N
#define M
int n,m,a,b,c;
struct Edge
{
    int from,to,next;
    int val;
}edge[2*MAXN];
int head[MAXN],w;
void add_edge(int from,int to,int val){
    w++;
    edge[w].from=from;
    edge[w].to=to;
    edge[w].val=val;
    edge[w].next=head[from];
    head[from]=w;
}
bool vis1[MAXN],vis2[MAXN],must[MAXN];
void dfs(int now,bool *vis,int &anst){
    vis[now]=true;
    if(must[now]) anst+=1;
    int i,to,val;
    for(i=head[now];i!=-1;i=edge[i].next){
        to=edge[i].to;
        val=edge[i].val;
        if(vis[to]){
            if(must[now]&&val==0){
                anst=-1;
                return;
            }
            else if(must[now]&&val==1&&must[to]){
                anst=-1;
                return;
            }
            else if(must[now]&&val==2&&!must[to]){
                anst=-1;
                return;
            }
            else if(!must[now]&&val==0&&must[to]){
                anst=-1;
                return;
            }
            else if(!must[now]&&val==1&&!must[to]){
                anst=-1;
                return;
            }
            else if(!must[now]&&val==2){
                anst=-1;
                return;
            }
        }
        else{//vis[to]=false;
            if(must[now]&&val==0){
                anst=-1;
                return;
            }
            else if(must[now]&&val==1){
                must[to]=false;
                dfs(to,vis,anst);
            }
            else if(must[now]&&val==2){
                must[to]=true;
                dfs(to,vis,anst);
            }
            else if(!must[now]&&val==0){
                must[to]=false;
                dfs(to,vis,anst);
            }
            else if(!must[now]&&val==1){
                must[to]=true;
                dfs(to,vis,anst);
            }
            else if(!must[now]&&val==2){
                anst=-1;
                return;
            }
            if(anst==-1) return;
        }
    }
}
int main()
{
    cin>>n>>m;
    repin(i,1,n){
        head[i]=-1;
        vis1[i]=false;
        vis2[i]=false;
    }
    w=0;
    repin(i,1,m){
        scanf("%d %d %d",&a,&b,&c);
        add_edge(a,b,c);
        add_edge(b,a,c);
    }
    int ans=0,anst1,anst2;
    repin(i,1,n){
        if(vis1[i] || vis2[i]) continue;
        must[i]=true;
        anst1=0;
        dfs(i,vis1,anst1);
        must[i]=false;
        anst2=0;
        dfs(i,vis2,anst2);
        if(anst1==-1&&anst2==-1){
            printf("impossible\n");
            exit(0);
        }
        else if(anst1!=-1&&anst2==-1){
            ans+=anst1;
        }
        else if(anst1==-1&&anst2!=-1){
            ans+=anst2;
        }
        else ans+=min(anst1,anst2);
    }
    printf("%d\n",ans);
}







这题也不单单是高精度问题,需要将公式推出来

不难发现,Sn=C(n+1),然后求C(n)题目已经给了个公式C(n)=(2n,n)/(n+1);

(2n,n)就是排列组合中的组合问题,即2n个里选n个的总数,那么求(2n,n)复杂度就是O(n)的了

接下来就是用高精度来做,模拟下就出来了。


一开始我的思路是把每一个C(n)求出来,再求S(n),用java做T了

下面java7过的代码,c++高精度模版我还没有,以后要搞一个自己的

import java.io.*;
import java.util.*;
import java.math.BigInteger;

public class Main {
    public static void main(String[] args) throws Exception {
        Scanner cin=new Scanner(System.in);
        int n=cin.nextInt();
        BigInteger up,down;
        up=down=new BigInteger("1");
        BigInteger tt=new BigInteger((2*n+2)+"");
        BigInteger one=new BigInteger("1");
        for(int i=1;i<=n+1;i++){
            BigInteger t=new BigInteger(i+"");
            down=down.multiply(t);
            up=up.multiply(tt);
            tt=tt.subtract(one);
        }
        BigInteger ans=up.divide(down);
        BigInteger t1=new BigInteger((n+2)+"");
        ans=ans.divide(t1);
        System.out.println(ans);
    }
}




这题就是求期望分数

期望分数=所有的 (分数*该分数占的概率)

原谅我偷懒不写出数学公式来了0.0

最后判断浮点相等别忘了eps

代码如下:

//Hello. I'm Peter.
#include<cstdio>
#include<iostream>
#include<sstream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<cctype>
#include<ctime>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double ld;
#define peter cout<<"i am peter"<<endl
#define input freopen("data.txt","r",stdin)
#define randin srand((unsigned int)time(NULL))
#define INT (0x3f3f3f3f)*2
#define LL (0x3f3f3f3f3f3f3f3f)*2
#define gsize(a) (int)a.size()
#define len(a) (int)strlen(a)
#define slen(s) (int)s.length()
#define pb(a) push_back(a)
#define clr(a) memset(a,0,sizeof(a))
#define clr_minus1(a) memset(a,-1,sizeof(a))
#define clr_INT(a) memset(a,INT,sizeof(a))
#define clr_true(a) memset(a,true,sizeof(a))
#define clr_false(a) memset(a,false,sizeof(a))
#define clr_queue(q) while(!q.empty()) q.pop()
#define clr_stack(s) while(!s.empty()) s.pop()
#define rep(i, a, b) for (int i = a; i < b; i++)
#define dep(i, a, b) for (int i = a; i > b; i--)
#define repin(i, a, b) for (int i = a; i <= b; i++)
#define depin(i, a, b) for (int i = a; i >= b; i--)
#define pi acos(-1.0)
#define eps 1e-6
#define MOD 1000000007
#define MAXN 100100
#define N
#define M 1000
int a1,b1,a2,b2,n1,n2;
int number1[M],number2[M];
double avepoint1,avepoint2;
int dcmp(double x){
    if(fabs(x)<eps) return 0;
    else if(x<0) return -1;
    else return 1;
}
int main()
{
    cin>>a1>>b1>>a2>>b2;
    repin(i,a1,b1){
        repin(j,a2,b2){
            number1[i+j]+=1;
        }
    }
    n1=(b1-a1+1)*(b2-a2+1);
    avepoint1=0.0;
    repin(i,a1+a2,b1+b2){
        double t=(double)1.0*number1[i]/n1;
        avepoint1+=t*i;
    }
    
    cin>>a1>>b1>>a2>>b2;
    repin(i,a1,b1){
        repin(j,a2,b2){
            number2[i+j]+=1;
        }
    }
    n2=(b1-a1+1)*(b2-a2+1);
    avepoint2=0.0;
    repin(i,a1+a2,b1+b2){
        double t=(double)1.0*number2[i]/n2;
        avepoint2+=t*i;
    }
    int t=dcmp(avepoint1-avepoint2);
    if(t==0) printf("Tie\n");
    else if(t<0) printf("Emma\n");
    else printf("Gunnar\n");
}



这题是贪心问题。

我不知道为什么是对的,和队友讨论了后,得出了个结论,但没有严格证明,没有图也不好说,就不陈述了。

将数列从小到大排序,从后往前扫,假设这个点左边全部用横向消除方法,右边全部用纵向消除方法

每次左边和右边的方法都可以知道需要多少步,维护最小值即可

代码如下:

//Hello. I'm Peter.
#include<cstdio>
#include<iostream>
#include<sstream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<cctype>
#include<ctime>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double ld;
#define peter cout<<"i am peter"<<endl
#define input freopen("data.txt","r",stdin)
#define randin srand((unsigned int)time(NULL))
#define INT (0x3f3f3f3f)*2
#define LL (0x3f3f3f3f3f3f3f3f)*2
#define gsize(a) (int)a.size()
#define len(a) (int)strlen(a)
#define slen(s) (int)s.length()
#define pb(a) push_back(a)
#define clr(a) memset(a,0,sizeof(a))
#define clr_minus1(a) memset(a,-1,sizeof(a))
#define clr_INT(a) memset(a,INT,sizeof(a))
#define clr_true(a) memset(a,true,sizeof(a))
#define clr_false(a) memset(a,false,sizeof(a))
#define clr_queue(q) while(!q.empty()) q.pop()
#define clr_stack(s) while(!s.empty()) s.pop()
#define rep(i, a, b) for (int i = a; i < b; i++)
#define dep(i, a, b) for (int i = a; i > b; i--)
#define repin(i, a, b) for (int i = a; i <= b; i++)
#define depin(i, a, b) for (int i = a; i >= b; i--)
#define pi acos(-1.0)
#define eps 1e-6
#define MOD 1000000007
#define MAXN 100100
#define N
#define M 1000
int n,ans;
int h[MAXN];
int main()
{
    cin>>n;
    repin(i,1,n){
        scanf("%d",h+i);
    }
    sort(h+1,h+1+n);
    ans=n;
    depin(i,n,1){
        int t=h[i]+(n-i);
        ans=min(ans,t);
    }
    cout<<ans<<endl;
}




给两个时钟,每个时钟有n个指针,方向散乱无序,告诉你12点钟方向顺时针转到该指针的角度是多少

问,将第一个时钟旋转某个角度,是否可以和第二个时钟完全重合?

只需要输出是否即可,不需要知道旋转多少度


思路如下

将2个时钟指针角度都从小到大排序

每个时钟求出下一个指针和上一个指针的角度差,构成2个数组(注意这个过程末尾和第一个指针构成的角度)

现在需要做的是,判断下一个数组头尾移动后,能否和第一个数组重合。


将第一个数组复制一遍,从n长度,变成2n,d1[i+n]==d[i]

那么,问题就变成了,下面这个长度为n的数组,是否是上面那个长度为2n数组的子串

跑一发kmp就出来了


代码如下:

//Hello. I'm Peter.
#include<cstdio>
#include<iostream>
#include<sstream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<cctype>
#include<ctime>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double ld;
#define peter cout<<"i am peter"<<endl
#define input freopen("data.txt","r",stdin)
#define randin srand((unsigned int)time(NULL))
#define INT (0x3f3f3f3f)*2
#define LL (0x3f3f3f3f3f3f3f3f)*2
#define gsize(a) (int)a.size()
#define len(a) (int)strlen(a)
#define slen(s) (int)s.length()
#define pb(a) push_back(a)
#define clr(a) memset(a,0,sizeof(a))
#define clr_minus1(a) memset(a,-1,sizeof(a))
#define clr_INT(a) memset(a,INT,sizeof(a))
#define clr_true(a) memset(a,true,sizeof(a))
#define clr_false(a) memset(a,false,sizeof(a))
#define clr_queue(q) while(!q.empty()) q.pop()
#define clr_stack(s) while(!s.empty()) s.pop()
#define rep(i, a, b) for (int i = a; i < b; i++)
#define dep(i, a, b) for (int i = a; i > b; i--)
#define repin(i, a, b) for (int i = a; i <= b; i++)
#define depin(i, a, b) for (int i = a; i >= b; i--)
#define pi acos(-1.0)
#define eps 1e-6
#define MOD 1000000007
#define MAXN 200100
#define N
#define M
int n;
int a[MAXN],b[MAXN];
int d1[2*MAXN],d2[MAXN];
int nextpos[MAXN];
void Build_nextpos(){
    int i,j;
    i=0;
    nextpos[0]=j=-1;
    while(i<n){
        if(j==-1 || d2[i]==d2[j]){
            nextpos[i+1]=j+1;
            if(d2[j+1]==d2[i+1]) nextpos[i+1]=nextpos[j+1];
            i++;
            j=j+1;
        }
        else j=nextpos[j];
    }
}
bool kmp(){
    int i,j;
    i=j=0;
    while(i<2*n && j<n){
        if(j==-1 || d1[i]==d2[j]){
            i++;
            j++;
        }
        else j=nextpos[j];
    }
    if(j==n) return true;
    else return false;
}
int main()
{
    cin>>n;
    rep(i,0,n){
        scanf("%d",a+i);
    }
    sort(a,a+n);
    rep(i,0,n){
        scanf("%d",b+i);
    }
    sort(b,b+n);
    rep(i,0,n){
        if(i==n-1) d1[i]=360000-a[i]+a[0];
        else d1[i]=a[i+1]-a[i];
    }
    rep(i,n,2*n){
        d1[i]=d1[i-n];
    }
    rep(i,0,n){
        if(i==n-1) d2[i]=360000-b[i]+b[0];
        else d2[i]=b[i+1]-b[i];
    }
    Build_nextpos();
    if(kmp()) printf("possible\n");
    else printf("impossible\n");
}




简单模拟题

判断火车人数是否小于0

判断火车人数是否超过限制

判断火车是否存在人没满但却有人等待的情况

判断最终火车是否为空

代码如下:

//Hello. I'm Peter.
#include<cstdio>
#include<iostream>
#include<sstream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<cctype>
#include<ctime>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double ld;
#define peter cout<<"i am peter"<<endl
#define input freopen("data.txt","r",stdin)
#define randin srand((unsigned int)time(NULL))
#define INT (0x3f3f3f3f)*2
#define LL (0x3f3f3f3f3f3f3f3f)*2
#define gsize(a) (int)a.size()
#define len(a) (int)strlen(a)
#define slen(s) (int)s.length()
#define pb(a) push_back(a)
#define clr(a) memset(a,0,sizeof(a))
#define clr_minus1(a) memset(a,-1,sizeof(a))
#define clr_INT(a) memset(a,INT,sizeof(a))
#define clr_true(a) memset(a,true,sizeof(a))
#define clr_false(a) memset(a,false,sizeof(a))
#define clr_queue(q) while(!q.empty()) q.pop()
#define clr_stack(s) while(!s.empty()) s.pop()
#define rep(i, a, b) for (int i = a; i < b; i++)
#define dep(i, a, b) for (int i = a; i > b; i--)
#define repin(i, a, b) for (int i = a; i <= b; i++)
#define depin(i, a, b) for (int i = a; i >= b; i--)
#define pi acos(-1.0)
#define eps 1e-6
#define MOD 1000000007
#define MAXN 100100
#define N
#define M 1000
int c,n,nowcapacity;
void impossible(){
    printf("impossible\n");
    exit(0);
}
int main()
{
    cin>>c>>n;
    nowcapacity=0;
    int out,in,wait;
    repin(i,1,n){
        scanf("%d %d %d",&out,&in,&wait);
        nowcapacity-=out;
        if(nowcapacity<0) impossible();
        nowcapacity+=in;
        if(nowcapacity>c) impossible();
        if(nowcapacity!=c && wait!=0) impossible();
    }
    if(nowcapacity!=0) impossible();
    printf("possible\n");
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值