2017-2018 CTU Open Contest

A - Amusement Anticipation

题意:找到间隔相同的最长的子串,这个串以最后一个元素为开头

#include 
#include 
#include 
using namespace std;
 
int main()
{
    long long a[1000+10], ans;
    int n, i;
    while(scanf("%d",&n)!=EOF)
    {
       int f = 1;
        ans = 0;
        for(i = 1; i<=n; i++)
            scanf("%lld",&a[i]);
            ans = a[n]-a[n-1];
        for(i = n; i>=1; i--)
        {
          if(a[i]-a[i-1]!=ans)
          {
           printf("%d\n",i);
           f = 0;
           break;
          }
        }
        if(f==1)
        printf("1\n");
    }
    return 0;
}

B - Pond Cascade

题意:给出n个水池,大小不同,给出流速,当一个水池装满水后会溢出,求最后一个水池装满的时间和全部装满的时间。

分析:这个题有三种做法,二分 / 优先队列 / 贪心

二分:规定一下二分的次数

#include
using namespace std;
const int N=1e5+10;
const double eps=1e-7;
int n;
double F,cap[N],flow[N];

bool judge(double t,int flag)
{
    for(int i=0; icap[i])flow[i+1]+=flow[i]-cap[i];
        else if(flag)return false;
    }
    return flow[n-1]>cap[n-1];
}

int main()
{
    //freopen("i.txt","r",stdin);
    while(scanf("%d%lf",&n,&F)==2)
    {
        for(int i=0; i

优先队列:每次求最先装满的那个,用双向链表保存前后水池关系

#include 
#include 
#include 
#include 
#include 
using namespace std;
const int maxn = 1e5 + 7;
int n;
double f;
int hail[maxn],tial[maxn];//链表头尾
bool vis[maxn];
double cap[maxn];//剩余容量
double t[maxn];//总时间
double lt[maxn];//更新容量前的时间
double flow[maxn];//流速
struct Node{
    int id;
    double time;
    bool operator < (const Node& rhs) const {
        return time > rhs.time;
    }
};
priority_queueq;
int main(){
    while(~scanf("%d%lf",&n,&f)){
        double last_time = 0,tagert_time = 0;
        while(!q.empty()) q.pop();
        memset(vis, 0, sizeof(vis));
        memset(t, 0, sizeof(t));
        memset(lt, 0, sizeof(lt));
        for(int i=1;i<=n;i++){
            hail[i] = i-1;
            tial[i] = i+1;
            flow[i] = f;
            scanf("%lf",&cap[i]);
            t[i] = cap[i]/f;
            q.push({i,t[i]});
            //cout<

 

贪心:对于输出第n个满的时间,第n个可能是单独的不靠前面的流向它或者靠前面的流向它,时间就是后面m个的总容量除以后面m个的总速度的最小值就是第n个的时间。而最后流满的时间是第一个流满时间,第一个和第二个加起来流满时间,第1,2,3个加起来流满时间,第……的最大值

#include 
#include 
#include 
#include 
#include 
using namespace std;
const int maxn = 1e5 + 7;
int n;
double f;
double cap[maxn];

int main(){
    while(~scanf("%d%lf",&n,&f)){
        for(int i=1;i<=n;i++)
            scanf("%lf",&cap[i]);
        double sum = cap[n] , flow = f;
        double res1 = cap[n]/f;
        for(int i=n-1;i>=1;i--){
            sum += cap[i];
            flow += f;
            res1 = min(res1,sum/flow);
        }
        double res2 = cap[1]/f;
        sum = cap[1];
        flow = f;
        for(int i=2;i<=n;i++){
            sum += cap[i];
            flow += f;
            res2 = max(res2,sum/flow);
        }
        printf("%.8f %.8f\n",res1,res2);
    }
}

C - Chessboard Dancing

#include
using namespace std;
int main()
{
    //freopen("i.txt","r",stdin);
    int n;
    char c;
    while(~scanf("%d %c",&n,&c))
    {
        if(c=='K'){
            if(n==1) cout<<1<

D - Equinox Roller Coaster

E - Forest Picture

题意:模拟,队友写的

#include
using namespace std;
char g[200][200];
int m,n;
void init()
{
    for(int i=0; i<=m+1; i++)
    {
        for(int j=0; j<=m+1; j++)
        {
            if(!i||!j||i==m+1||j==m+1)
                g[i][j]='*';
            else
                g[i][j]='.';
        }
    }
}
void test()
{
    for(int i=0; i<=m+1; i++)
    {
        for(int j=0; j<=m+1; j++)
        {
            cout<=1&&a<=m&&b>=1&&b<=m)
        return true;
    return false;
}
void getstump(int x,int y)
{
    if(ok(x,y))
        g[x][y]='o';
    if(ok(x,y-1))
        g[x][y-1]='_';
    if(ok(x,y+1))
        g[x][y+1]='_';
}
void gettree(int h,int x,int y)
{
    if(ok(x,y))
        g[x][y]='|';
    if(ok(x,y-1))
        g[x][y-1]='_';
    if(ok(x,y+1))
        g[x][y+1]='_';
    for(int i=1; i<=h; i++)
    {
        int a=x-i;
        if(ok(x-i,y))
            g[x-i][y]='|';
        if(ok(x-i,y-1))
            g[x-i][y-1]='/';
        if(ok(x-i,y+1))
            g[x-i][y+1]='\\';
    }
    if(ok(x-h-1,y))
        g[x-h-1][y]='^';
}
int main()
{
    //freopen("i.txt","r",stdin);
    while(~scanf("%d %d",&m,&n))
    {
        init();
        while(n--)
        {
            int a,b,c;
            scanf("%d %d %d",&a,&b,&c);
            b=b+1;
            c=m-c;
            if(!a)
                getstump(c,b);
            else
                gettree(a,c,b);
        }
        test();
        cout<

F - Shooting Gallery

题意:给出一串数字,相同数字可连起来形成一个区间,求最大的区间覆盖数

分析:DP

记忆化搜索

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define ll long long
#define lowbit(x) (x&(-x))
#define mem(a,b) memset(a,b,sizeof(a))
#define FRER() freopen("in.txt","r",stdin);
#define FREW() freopen("out.txt","w",stdout);
using namespace std;
typedef pair pii;
const int maxn = 5000 + 7, inf = 0x3f3f3f3f;
int dp[maxn][maxn];
int n;
int a[maxn];
int dfs(int L,int R){
    if(L>=R) return 0;
    if(dp[L][R]!=-1) return dp[L][R];
    if(a[L]==a[R]) return dp[L][R] = 1 + dfs(L+1, R-1);
    else return dp[L][R] = max(dfs(L+1, R), dfs(L,R-1));
}
int main(){
    //FRER();
    while(~scanf("%d",&n)){
        for(int i=0;i<=n;i++)
            for(int j=0;j<=n;j++)
                dp[i][j] = -1;
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        printf("%d\n",dfs(1, n));
    }
}

 

区间DP

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define ll long long
#define lowbit(x) (x&(-x))
#define mem(a,b) memset(a,b,sizeof(a))
#define FRER() freopen("in.txt","r",stdin);
#define FREW() freopen("out.txt","w",stdout);
using namespace std;
typedef pair pii;
const int maxn = 5000 + 7, inf = 0x3f3f3f3f;
int dp[maxn][maxn];
int n;
int a[maxn];
int main(){
    //FRER();
    while(~scanf("%d",&n)){
        for(int i=0;i<=n;i++)
            for(int j=0;j<=n;j++)
                dp[i][j] = 0;
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        for(int len=2;len<=n;len++){
            for(int i=1;i+len-1<=n;i++){
                if(a[i]==a[i+len-1]){
                    dp[i][i+len-1] = max(dp[i][i+len-1],dp[i+1][i+len-2]+1);
                }
                else dp[i][i+len-1] = max(dp[i+1][i+len-1],dp[i][i+len-2]);
                //printf("dp[%d][%d] = %d\n",i,i+len-1,dp[i][i+len-1]);
            }
        }
        cout<

G - Ice cream samples 

尺取法

#include 
#include 
#include 
#include 
#include 
using namespace std;
const int maxn = 2e6 + 7, inf = 0x3f3f3f3f;
int n,k,m;
int cnt;
int ans;
struct Node{
    int len;
    vectorv;
}s[maxn];
int vis[maxn],sum[maxn];
int main(){
    while(~scanf("%d%d",&n,&k)){
        cnt = 0;
        ans = inf;
        memset(vis, 0, sizeof(vis));
        for(int i=1;i<=n;i++){
            scanf("%d",&s[i].len);
            for(int j=1;j<=s[i].len;j++){
                scanf("%d",&m);
                s[i].v.push_back(m);
            }
            sum[i] = s[i].len;
            sum[i+n] = sum[i];
            s[i+n] = s[i];
        }
        for(int i=1;i<=2*n;i++)
            sum[i]+=sum[i-1];
        int l = 1 , r = 1;
        while(l<=r){
            if(r-l+1>n) break;
            while(cnt=2*n+1) break;
            if(cnt==k){
                ans = min(ans,sum[r-1]-sum[l-1]);
                for(int i=0;i

H - Dark Ride with Monsters

题意:给出一个序列,问交换几次可以使得序列有序,暴力

#include
using namespace std;
const int maxn=2*1e5+10;
int s[maxn],t[maxn],m[10*maxn];
int main()
{
    //freopen("i.txt","r",stdin);
    int n;
    while(~scanf("%d",&n))
    {
        for(int i=0;iq;
        int ans=0;
        for(int i=0;i

I - Go Northwest!

题意:给出若干个点,求所有两个点的组合中,在一条对角线的组合的比率

#include
using namespace std;
typedef map ma;
ma m;
int main()
{
   //freopen("i.txt","r",stdin);
   long long n;
   while(~scanf("%lld",&n))
   {
       m.clear();
       long long N=n*n;
       while(n--)
       {
           long long x,y;
           scanf("%lld %lld",&x,&y);
           m[x+y]++;
           m[x-y]++;
       }
       long long M=0;
       for(ma::iterator it=m.begin();it!=m.end();it++)
       {
           M+=(it->second)*(it->second-1);
       }
       printf("%.8f\n",(double)M/N);
   }
}

J - Punching Power

题意:给你二维平面的一些点,让你从这n个点中选择一些点,让这些点任意两点的距离要大于1.3

分析:二分图匹配,把相距为1的点建边,跑出最大匹配ans,n-ans即为答案

#include
using namespace std;
const int N=2000+10;
const int M=N*20;
int n;
int head[N],to[M],nxt[M],nEdge;
int x[N],y[N],op[N],vis[N];

void AddEdge(int u,int v)
{
    nxt[nEdge]=head[u],to[nEdge]=v,head[u]=nEdge++;
}

bool match(int u)
{
    //printf("u=%d\n",u);
    for(int e=head[u];~e;e=nxt[e])
    {
        int v=to[e];
        if(vis[v])continue;
        vis[v]=1;
        if(!~op[v]||match(op[v]))
        {
            op[v]=u,op[u]=v;
            return true;
        }
    }
    return false;
}

int main()
{
    //freopen("i.txt","r",stdin);
    while(scanf("%d",&n)==1)
    {
        memset(head,-1,sizeof head);
        nEdge=0;
        for(int i=0; i

K - Treetop Walkway

 

你可能感兴趣的:(2017-2018 CTU Open Contest)