2017-2018 CTU Open Contest

A - Amusement Anticipation

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

#include <iostream>
#include <stdio.h>
#include <bits/stdc++.h>
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<bits/stdc++.h>
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; i<n; ++i)flow[i]=F*t;
    for(int i=0; i<n-1; ++i)
    {
        if(flow[i]>cap[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<n; ++i)
            scanf("%lf",&cap[i]);
        //for(int i=0;i<n;++i)printf("%f\n",cap[i]);
        double ans1,ans2;
        double l=0,r=1e9+10;
        for(int i=0;i<100;++i)
        {
            double mid=(l+r)/2.0;
            judge(mid,0)?r=mid:l=mid;
        }
        ans1=l;
        l=0,r=1e9+10;
        for(int i=0;i<100;++i)
        {
            double mid=(l+r)/2.0;
            judge(mid,1)?r=mid:l=mid;
        }
        ans2=l;
        printf("%.8f %.8f\n",ans1,ans2);
    }
    return 0;
}

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

#include <iostream>
#include <algorithm>
#include <queue>
#include <cstdio>
#include <cstring>
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_queue<Node>q;
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<<t[i]<<endl;
        }
        hail[n+1] = n;
        tial[0] = 1;
        while(!q.empty()){
            Node now = q.top();q.pop();
            if(vis[now.id]) continue;
            vis[now.id] = true;
            last_time = now.time;
            //cout<<last_time<<endl;
            if(now.id == n) tagert_time = last_time;
            int fr = hail[now.id];
            int nx = tial[now.id];
            hail[nx] = fr;
            tial[fr] = nx;
            if(nx!=n+1){
                cap[nx] -= (last_time - lt[nx])*flow[nx];
                flow[nx] += flow[now.id];
                lt[nx] = last_time;
                t[nx] = cap[nx]/flow[nx];
                q.push({nx,t[nx]+lt[nx]});
            }
        }
        printf("%.8f %.8f\n",tagert_time,last_time);
    }
}

 

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

#include <iostream>
#include <algorithm>
#include <queue>
#include <cstdio>
#include <cstring>
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<bits/stdc++.h>
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<<endl;
            else cout<<4<<endl;
        }
        else if(c=='N'){
            if(n==1||n==2) cout<<1<<endl;
            else cout<<2<<endl;
        }
        else cout<<n<<endl;
    }
}

D - Equinox Roller Coaster

E - Forest Picture

题意:模拟,队友写的

#include<bits/stdc++.h>
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<<g[i][j];
        }
        cout<<endl;
    }
}
bool ok(int a,int b)
{
    if(a>=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<<endl;
    }
}

F - Shooting Gallery

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

分析:DP

记忆化搜索

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <queue>
#include <stack>
#include <string>
#include <cstdio>
#include <vector>
#include <iomanip>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <deque>
#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<int,int> 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 <map>
#include <set>
#include <list>
#include <cmath>
#include <queue>
#include <stack>
#include <string>
#include <cstdio>
#include <vector>
#include <iomanip>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <deque>
#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<int,int> 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<<dp[1][n]<<endl;
    }
}

G - Ice cream samples 

尺取法

#include <iostream>
#include <algorithm>
#include <queue>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 2e6 + 7, inf = 0x3f3f3f3f;
int n,k,m;
int cnt;
int ans;
struct Node{
    int len;
    vector<int>v;
}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<k&&r<=2*n){
                for(int i=0;i<s[r].len;i++){
                    m = s[r].v[i];
                    if(!vis[m]) cnt++;
                    vis[m]++;
                }
                r++;
            }
            if(r>=2*n+1) break;
            if(cnt==k){
                ans = min(ans,sum[r-1]-sum[l-1]);
                for(int i=0;i<s[l].len;i++){
                    m = s[l].v[i];
                    vis[m]--;
                    if(!vis[m]) cnt--;
                }
                l++;
            }
        }
        printf("%d\n",ans==inf?-1:ans);
        for(int i=1;i<=2*n;i++){
            s[i].v.clear();
        }
    }
}

H - Dark Ride with Monsters

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

#include<bits/stdc++.h>
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;i<n;i++)
        {
            scanf("%d",&s[i]);
            t[i]=s[i];
        }
        sort(t,t+n);
        for(int i=0;i<n;i++)
            m[t[i]]=i;
        queue<int>q;
        int ans=0;
        for(int i=0;i<n;i++)
        {
            int tep=m[s[i]];
            while(tep!=i)
            {
                swap(s[i],s[tep]);
                ans++;
                tep=m[s[i]];
            }
        }
        printf("%d\n",ans);
    }
}

I - Go Northwest!

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

#include<bits/stdc++.h>
using namespace std;
typedef map<long long,long long> 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<bits/stdc++.h>
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<n; ++i)
            scanf("%d%d",&x[i],&y[i]);
        for(int i=0; i<n; ++i)
            for(int j=i+1; j<n; ++j)
            {
                if((abs(x[i]-x[j])==1&&y[i]==y[j])||(abs(y[i]-y[j])==1&&x[i]==x[j]))
                {
                    AddEdge(i,j);
                    AddEdge(j,i);
                }
            }
        //printf("nedge=%d\n",nEdge);
        int ans=0;
        memset(op,-1,sizeof op);
        for(int i=0;i<n;++i)
        {
            memset(vis,0,sizeof vis);
            if(!~op[i]&&match(i))++ans;
        }
        printf("%d\n",n-ans);
    }
    return 0;
}

K - Treetop Walkway

 

猜你喜欢

转载自blog.csdn.net/Insist_77/article/details/83301716