2018 “百度之星”程序设计大赛 - 初赛(A)

度度熊拼三角

 
 Accepts: 2536
 
 Submissions: 4433
 Time Limit: 2000/1000 MS (Java/Others)
 
 Memory Limit: 65536/65536 K (Java/Others)
Problem Description

度度熊有 NN 根木棒,每根木棒的长度为a_iai​​。

现在要挑选其中的三根,问能拼出的三角形的最大周长是多少。

如果不能拼成任何一个三角形,输出 -11。

Input

多组数据(不超过1010组),读到EOF结束。

对于每一组数据:

第一行一个数 NN 表示木棒数量。

第二行一共 NN 个数,描述每一根木棒的长度。

1 \leq N \leq 10001N1000

木棒长度都是不超过100000100000的正整数

Output

对于每一组数据,输出一个数表示答案。

Sample Input
3
1 1 100
7
1 9 9 90 2 2 4
Sample Output
-1
22

A最大的连续选三根

两边之和大于第三边推广就是两小边大于大边就好了

#include<bits/stdc++.h>
using namespace std;
const int N=1005;
int a[N];
int main()
{
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int n;
    while(cin>>n)
    {
        for(int i=0; i<n; i++)cin>>a[i];
        sort(a,a+n);
        int ans=-1;
        for(int i=n-3; i>=0; i--)
            if(a[i]+a[i+1]>a[i+2])
            {
                ans=a[i]+a[i+1]+a[i+2];
                break;
            }
        cout<<ans<<"\n";
    }
    return 0;
}

本来sb的n^2logn的写法

#include<stdio.h>
#include<bits/stdc++.h>
using namespace std;
#define lson l,(l+r)/2,rt<<1
#define rson (l+r)/2+1,r,rt<<1|1
#define dbg(x) cout<<#x<<" = "<< (x)<< endl
#define pb push_back
#define fi first
#define se second
#define ll long long
#define sz(x) (int)(x).size()
#define pll pair<long long,long long>
#define pii pair<int,int>
#define pq priority_queue
const int N=1e5+5,MD=1e9+7,INF=0x3f3f3f3f;
const ll LL_INF=0x3f3f3f3f3f3f3f3f;
const double eps=1e-9,e=exp(1),PI=acos(-1.);
int a[N];
int main()
{
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int n;
    while(cin>>n)
    {
        int a[1005];
        for(int i=0; i<n; i++)cin>>a[i];
        sort(a,a+n);
        int ans=-1;
        for(int i=0;i<n;i++)
            for(int j=i+1;j<n;j++)
            {
                int y=a[j]+a[i];
                int pos=lower_bound(a+j+1,a+n,y)-a;
                if(pos-1==j)continue;
                ans=max(ans,a[i]+a[j]+a[pos-1]);
            }
        cout<<ans<<"\n";
    }
    return 0;
}

度度熊学队列

 
 Accepts: 958
 
 Submissions: 5545
 Time Limit: 3000/1500 MS (Java/Others)
 
 Memory Limit: 131072/131072 K (Java/Others)
Problem Description

度度熊正在学习双端队列,他对其翻转和合并产生了很大的兴趣。

初始时有 NN 个空的双端队列(编号为 11 到 NN ),你要支持度度熊的 QQ 次操作。

1uwvalval 在编号为 uu 的队列里加入一个权值为 valval 的元素。(w=0w=0 表示加在最前面,w=1w=1 表示加在最后面)。

2uww 询问编号为 uu 的队列里的某个元素并删除它。( w=0w=0 表示询问并操作最前面的元素,w=1w=1 表示最后面)

3uvww 把编号为 vv 的队列“接在”编号为 uu 的队列的最后面。w=0w=0 表示顺序接(队列 vv 的开头和队列 uu 的结尾连在一起,队列vv 的结尾作为新队列的结尾), w=1w=1 表示逆序接(先将队列 vv 翻转,再顺序接在队列 uu 后面)。且该操作完成后,队列 vv 被清空。

Input

有多组数据。

对于每一组数据,第一行读入两个数 NN 和 QQ。

接下来有 QQ 行,每行 33~44 个数,意义如上。

N \leq 150000,Q \leq 400000N150000,Q400000

1 \leq u,v \leq N,0 \leq w \leq 1,1 \leq val \leq 1000001u,vN,0w1,1val100000

所有数据里 QQ 的和不超过500000500000

Output

对于每组数据的每一个操作②,输出一行表示答案。

注意,如果操作②的队列是空的,就输出-11且不执行删除操作。

Sample Input
2 10
1 1 1 23
1 1 0 233
2 1 1 
1 2 1 2333
1 2 1 23333
3 1 2 1
2 2 0
2 1 1
2 1 0
2 1 1
Sample Output
23
-1
2333
233
23333

提示

由于读入过大,C/C++ 选手建议使用读入优化。

一个简单的例子:

void read(int &x){
	char ch = getchar();x = 0;
	for (; ch < '0' || ch > '9'; ch = getchar());
	for (; ch >='0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
}

B不卡时间,不像上次ZOJ月赛还卡时间,直接过就行了

#include<bits/stdc++.h>
using namespace std;
void read(int &x)
{
    char ch = getchar();
    x = 0;
    for (; ch < '0' || ch > '9'; ch = getchar());
    for (; ch >='0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
}
list<int>li[150005];
int main()
{
    int n,q;
    while(~scanf("%d%d",&n,&q))
    {
        for(int i=1; i<=n; i++)li[i].clear();
        for(int i=1,op,u,v,w,val; i<=q; i++)
        {
            read(op);
            switch(op)
            {
            case 1:
            {
                read(u),read(w),read(val);
                if(w==1)li[u].push_back(val);
                else li[u].push_front(val);
                break;
            }
            case 2:
            {
                read(u),read(w);
                if(w==1)
                {
                    if(li[u].empty())printf("-1\n");
                    else
                    {
                        printf("%d\n",*li[u].rbegin()),li[u].pop_back();
                    }
                }
                else
                {
                    if(li[u].empty())printf("-1\n");
                    else printf("%d\n",*li[u].begin()),li[u].pop_front();
                }
                break;
            }
            case 3:
            {
                read(u),read(v),read(w);
                if(w==1)li[v].reverse(),li[u].splice(li[u].end(),li[v]),li[v].clear();
                else li[u].splice(li[u].end(),li[v]),li[v].clear();
            }
            }
        }
    }
    return 0;
}

度度熊剪纸条

 
 Accepts: 488
 
 Submissions: 5471
 Time Limit: 2000/1000 MS (Java/Others)
 
 Memory Limit: 65536/65536 K (Java/Others)
Problem Description

度度熊有一张纸条和一把剪刀。

纸条上依次写着 NN 个数字,数字只可能是 00 或者 11。

度度熊想在纸条上剪 KK 刀(每一刀只能剪在数字和数字之间),这样就形成了 K+1K+1 段。

他再把这 K+1K+1 段按一定的顺序重新拼起来。

不同的剪和接的方案,可能会得到不同的结果。

度度熊好奇的是,前缀 11 的数量最多能是多少。

Input

有多组数据,读到EOF结束。

对于每一组数据,第一行读入两个数 NN 和 KK 。

第二行有一个长度为 NN 的字符串,依次表示初始时纸条上的 NN 个数。

0 \leq K < N \leq 100000K<N10000

所有数据 NN 的总和不超过100000100000

Output

对于每一组数据,输出一个数,表示可能的最大前缀 11 的数量。

Sample Input
5 1
11010
5 2
11010
Sample Output
2
3

可以考虑在哪里下刀,肯定是在1将要开始的地方,然后头尾也是特殊的

#include <bits/stdc++.h>
using namespace std;
#define fi second
#define se first
const int N=10005;
int a[N],dp[N];
char s[N];
pair<int,int>P[N];
int main()
{
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int n,k;
    while(cin>>n>>k)
    {
        cin>>s;
        int tot=0;
        for(int i=0; i<N; i++)P[i].fi=P[i].se=0;
        memset(dp,0,sizeof dp);
        for(int i=0; i<n; i++)
        {
            if(s[i]=='1') P[tot].fi++;
            else tot++;
        }
        if(s[0]=='1') P[0].se=1;
        if(s[n-1]=='1') P[tot].se=1,tot++;
        if(k==0)
        {
            if(s[0]=='1')  cout<<P[0].fi<<"\n";
            else cout<<"0\n";
        }
        else
        {
            int sum=0;
            if(s[0]=='1') sum+=P[0].fi;
            if(s[n-1]=='1'&&tot!=1) sum+=P[tot-1].fi;
            sort(P,P+tot,greater<pair<int,int> >());
            int pos=0;
            while(P[pos].se&&tot<n)pos++;
            P[pos].se=1;
            for(int j=0; j<tot; j++)
            {
                for(int i=k; i>1; i--)dp[i]=max(dp[i],dp[i-2+P[j].se]+P[j].fi);
                if(P[j].se==1)dp[1]=max(dp[1],dp[0]+P[j].fi);
            }
            cout<<max(sum,dp[k])<<"\n";
        }
    }
    return 0;
}

还有一种写法

#include <bits/stdc++.h>
using namespace std;

const int maxn = 10005;
int n, k, f[maxn];


string s;
int solve() 
{
  vector<pair<int, int>> vec;
  int p = 0;
  while(p < n) 
  {
    if(s[p] == '1') 
    {
      int j = p, tot = 0;
      while(j < n && s[j] == '1') 
      {
        tot++, j++;
      }
      if(p == 0) 
        vec.push_back(make_pair(tot, 1));
      else if(j == n) 
        vec.push_back(make_pair(tot, 1));
      else 
        vec.push_back(make_pair(tot, 2));
      p = j;
    }
    else p++;
  }
  if(k == 1) 
  {
    if(s[0] == '1') 
      return vec[0].first;
    return 0;
  }
  memset(f, 0, sizeof(f));
  for(int i = 0; i < vec.size(); i++) 
    for(int j = k; j >= vec[i].second; j--) 
      f[j] = max(f[j], f[j-vec[i].second]+vec[i].first);
  return f[k];
}
int main() 
{
  while(cin >> n >> k) 
  {
    cin >> s;k++;
    cout << solve() << endl;
  }
}

度度熊看球赛

 
 Accepts: 120
 
 Submissions: 491
 Time Limit: 2000/1000 MS (Java/Others)
 
 Memory Limit: 65536/65536 K (Java/Others)
Problem Description

世界杯正如火如荼地开展!度度熊来到了一家酒吧。

有 NN 对情侣相约一起看世界杯,荧幕前正好有 2 \times N2×N 个横排的位置。

所有人都会随机坐在某个位置上。

当然,如果某一对情侣正好挨着坐,他们就会有说不完的话,影响世界杯的观看。

一般地,对于一个就座方案,如果正好有 KK 对情侣正好是挨着坐的,就会产生 D^KDK​​ 的喧闹值。

度度熊想知道随机就座方案的期望喧闹值。

为了避免输出实数,设答案为 ansans,请输出 ans \times (2N)!ans×(2N)modmoPP 的值。其中 P=998244353P=998244353

Input

有多组数据(不超过 10001000 组),读到EOF结束。

对于每一组数据,读入两个数 NN 和 DD 。

1 \leq N,D \leq 10001N,D1000

Output

对于每一组数据,输出一个数表示答案。

Sample Input
1 10
2 3
Sample Output
20
104

读错题,竟然是一排有2*n个座位,然后找到递推式就好了

#include<bits/stdc++.h>
using namespace std;
int dp[1005][1005],C[2005][2005];
const int MD=998244353;
int main()
{
    int i,j;
    for (i=0; i<2005; i++)
    {
        C[i][0]=1;
        for (j=1; j<=i; j++)
            C[i][j]=(C[i-1][j-1]+C[i-1][j])%MD;
    }
    dp[0][0]=1;
    for(i=1; i<1005; i++) //2i个位置 j个相邻
    {
        for (j=0; j<i; j++)
        {
            if(dp[i-1][j]==0)continue;
            int t=(i-1)*2-j+1;//不会造成影响
            dp[i][j+1]=(dp[i][j+1]+2LL*dp[i-1][j]*C[t][1]%MD)%MD;//组1
            dp[i][j]=(dp[i][j]+2LL*dp[i-1][j]*C[t][2]%MD)%MD;//没有贡献
            if(j>0)dp[i][j-1]=(dp[i][j-1]+2LL*dp[i-1][j]*C[t][1]%MD*C[j][1]%MD)%MD;//拆1
            if(j>1)dp[i][j-2]=(dp[i][j-2]+2LL*dp[i-1][j]*C[j][2]%MD)%MD;//拆2
            dp[i][j]=(dp[i][j]+2LL*dp[i-1][j]*C[j][1]%MD)%MD;//拆1+组1
        }
    }
    int n,K;
    while (~scanf("%d%d",&n,&K))
    {
        int ans=0,t=1;
        for(i=0; i<=n; i++)ans=(ans+1LL*t*dp[n][i])%MD,t=1LL*t*K%MD;
        printf("%d\n",ans);
    }
    return 0;
}

 

posted @ 2018-08-19 14:27  暴力都不会的蒟蒻  阅读(473)  评论(0编辑  收藏  举报