BestCoder 1st Anniversary ($) 题解

Souvenir

问题描述
今天是BestCoder一周年纪念日. 比赛管理员Soda想要给每个参赛者准备一个纪念品. 商店里纪念品的单价是
     
      p
     元, 同时也可以花
     
      q
     元购买纪念品套装, 一个套装里有
     
      m
     个纪念品.

今天总共有
     
      n
     个参赛者, Soda想要知道最少需要花多少钱才可以给每个人都准备一个纪念品.
输入描述
输入有多组数据. 第一行有一个整数
     
      T
      
     
      (1T105)
     , 表示测试数据组数. 然后对于每组数据:

一行包含4个整数 
     
      n,m,p,q
      
     
      (1n,m,p,q104)
     .
输出描述
对于每组数据输出最小花费.
输入样例
2
1 2 2 1
1 2 3 4
输出样例
1
3
Hint
对于第一组数据, Soda可以1元购买一个套装. 对于第二组数据, Soda可以直接花3元购买一个纪念品.

代码:

// C
#ifndef _GLIBCXX_NO_ASSERT
#include <cassert>
#endif

#include <cctype>
#include <cerrno>
#include <cfloat>
#include <ciso646>
#include <climits>
#include <clocale>
#include <cmath>
#include <csetjmp>
#include <csignal>
#include <cstdarg>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>

// C++
#include <algorithm>
#include <bitset>
#include <complex>
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <iomanip>
#include <ios>
#include <iosfwd>
#include <iostream>
#include <istream>
#include <iterator>
#include <limits>
#include <list>
#include <locale>
#include <map>
#include <memory>
#include <new>
#include <numeric>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <streambuf>
#include <string>
#include <typeinfo>
#include <utility>
#include <valarray>
#include <vector>

using namespace std;

#define rep(i,j,k) for(int i=(int)j;i<(int)k;++i)
#define per(i,j,k) for(int i=(int)j;i>(int)k;--i)
#define lowbit(a) a&-a
#define Max(a,b) a>b?a:b
#define Min(a,b) a>b?b:a
#define mem(a,b) memset(a,b,sizeof(a))

typedef long long LL;
typedef unsigned long long LLU;
typedef double db;
const int N=1e5+10;
const int inf=0x3f3f3f3f;
int t,ans,res,cnt,tmp;

inline LL read()
{
    int c=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        c=c*10+ch-'0';
        ch=getchar();
    }
    return c*f;
}
int n,m,p,q;
int main()
{
    t=read();
    while(t--)
    {
        n=read();
        m=read();
        p=read();
        q=read();
        int h1=p*n;///全部买单价
        int h2,h3;
        if(n%m==0){///倍数关系
            h2 = n/m*q;///全部套装
        }
        else{  
            h2 = (n/m+1)*q;///人数不够的,加一
        }
        h3 = n/m*q + n%m*p;///n%m的零头买单价
        printf("%d\n",min(h1,min(h2,h3)));
    }
    return 0;
}


B Hidden String

问题描述
今天是BestCoder一周年纪念日. 比赛管理员Soda有一个长度为
   
    n
   的字符串
   
    s
   . 他想要知道能否找到
   
    s
   的三个互不相交的子串
   
    s[l1..r1]
   , 
   
    s[l2..r2]
   , 
   
    s[l3..r3]
   满足下列条件:

  1. 
   
    1l1r1<l2r2<l3r3n
   

  2. 
   
    s[l1..r1]
   , 
   
    s[l2..r2]
   , 
   
    s[l3..r3]
   依次连接之后得到字符串"anniversary".
输入描述
输入有多组数据. 第一行有一个整数
   
    T
    
   
    (1T100)
   , 表示测试数据组数. 然后对于每组数据:

一行包含一个仅含小写字母的字符串
   
    s
    
   
    (1|s|100)
   .
输出描述
对于每组数据, 如果Soda可以找到这样三个子串, 输出"YES", 否则输出"NO".
输入样例
2
annivddfdersewwefary
nniversarya
输出样例
YES
NO


代码:

// C
#ifndef _GLIBCXX_NO_ASSERT
#include <cassert>
#endif

#include <cctype>
#include <cerrno>
#include <cfloat>
#include <ciso646>
#include <climits>
#include <clocale>
#include <cmath>
#include <csetjmp>
#include <csignal>
#include <cstdarg>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>

// C++
#include <algorithm>
#include <bitset>
#include <complex>
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <iomanip>
#include <ios>
#include <iosfwd>
#include <iostream>
#include <istream>
#include <iterator>
#include <limits>
#include <list>
#include <locale>
#include <map>
#include <memory>
#include <new>
#include <numeric>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <streambuf>
#include <string>
#include <typeinfo>
#include <utility>
#include <valarray>
#include <vector>

using namespace std;

#define rep(i,j,k) for(int i=(int)j;i<(int)k;++i)
#define per(i,j,k) for(int i=(int)j;i>(int)k;--i)
#define lowbit(a) a&-a
#define Max(a,b) a>b?a:b
#define Min(a,b) a>b?b:a
#define mem(a,b) memset(a,b,sizeof(a))

typedef long long LL;
typedef unsigned long long LLU;
typedef double db;
const int N=1e5+10;
const int inf=0x3f3f3f3f;

char str[N];
bool vis[N];
int dir4[4][2]= {{1,0},{0,1},{-1,0},{0,-1}};
int dir8[8][2]= {{1,0},{1,1},{0,1},{-1,1},{-1,0},{-1,-1},{0,-1},{1,-1}};
int movv[5][2]= {{1,0},{0,1},{0,0},{-1,0},{0,-1}};

inline LL read()
{
    int c=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        c=c*10+ch-'0';
        ch=getchar();
    }
    return c*f;
}
int t,n,m,p,q,len;
int ok;
char s1[N];
char pp[12]="anniversary";
void dfs(int u,int k,int num)
{
    if(k==11&&num==3){
        ok=1;
        return ;
    }
    for(int i=u; i<len; ++i){
        int h1=k;
        while(s1[i]==pp[h1])
        {
            dfs(i+1,h1+1,num+1);
            i++;
            h1++;
        }
    }
}
int main()
{
    t=read();
    while(t--){
        scanf("%s",&s1);
        len=strlen(s1);
        ok=0;
        dfs(0,0,0);
        if(ok) puts("YES");
        else puts("NO");
    }
    return 0;
}
C Sequence

问题描述
Soda习得了一个数列, 数列的第
   
    n
    
   
    (n1)
   项是
   
    3n(n1)+1
   . 现在他想知道对于一个给定的整数
   
    m
   , 是否可以表示成若干项上述数列的和. 如果可以, 那么需要的最小项数是多少?

例如, 22可以表示为
   
    7+7+7+1
   , 也可以表示为
   
    19+1+1+1
   .
输入描述
输入有多组数据. 第一行有一个整数
   
    T
    
   
    (1T104)
   , 表示测试数据组数. 然后对于每组数据:

一行包含1个整数 
   
    m
    
   
    (1m109)
   .
输出描述
对于每组数据输出最小花费.
输入样例
10
1
2
3
4
5
6
7
8
22
10
输出样例
1
2
3
4
5
6
1
2
4
4
【解题思路】:AC率 1.7%,暂时没有想到好的解法~~

D Bipartite Graph

问题描述
Soda有一个
   
    n
   个点
   
    m
   条边的二分图, 他想要通过加边使得这张图变成一个边数最多的完全二分图. 于是他想要知道他最多能够新加多少条边. 注意重边是不允许的.
输入描述
输入有多组数据. 第一行有一个整数
   
    T
    
   
    (1T100)
   , 表示测试数据组数. 然后对于每组数据:

第一行报包含两个整数
   
    n
   
   
    m
   , 
   
    (2n10000,0m100000)
   .

接下来
   
    m
   行, 每行两个整数
   
    u
   
   
    v
   
   
    (1u,vn,vu)
   , 表示
   
    u
   
   
    v
   之间有一条无向边.

输入保证给出的图是二分图, 没有重边, 没有自环. 大部分数据都是小数据.
输出描述
对于每组数据, 输出Soda最多能加的边数.
输入样例
2
4 2
1 2
2 3
4 4
1 2
1 4
2 3
3 4
输出样例
2
0
【思路】:
首先二分图可以分成两类点
    
     X
    
    
     Y
    , 完全二分图的边数就是
    
     |X||Y|
    .我们的目的是
    
     max{|X||Y|}
    , 并且
    
     |X|+|Y|=n
    .

把原图黑白染色, 每个联通块有
    
     ai
    个黑点, 
    
     bi
    个白点, 于是就是要确定
    
     ai
    属于
    
     X
    还是属于
    
     Y
    . 然后我们考虑dp, 
    
     dpi,x
    表示用了前
    
     i
    个联通块, 
    
     |X|=x
    是否可行. dp方程很容易确定, 
    
     dpi,x=dpi1,xa[i] or dpi1,xb[i]
    .

直接暴力是
    
     O(n2)
    的, 可以考虑用bitset优化, 这样就可以过了. 实际上由于数据很难造, 一些稍加优化的
    
     n2
    也可以过的
代码:

#ifndef _GLIBCXX_NO_ASSERT
#include <cassert>
#endif

#include <cctype>
#include <cerrno>
#include <cfloat>
#include <ciso646>
#include <climits>
#include <clocale>
#include <cmath>
#include <csetjmp>
#include <csignal>
#include <cstdarg>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>

// C++
#include <algorithm>
#include <bitset>
#include <complex>
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <iomanip>
#include <ios>
#include <iosfwd>
#include <iostream>
#include <istream>
#include <iterator>
#include <limits>
#include <list>
#include <locale>
#include <map>
#include <memory>
#include <new>
#include <numeric>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <streambuf>
#include <string>
#include <typeinfo>
#include <utility>
#include <valarray>
#include <vector>

using namespace std;

#define rep(i,j,k) for(int i=(int)j;i<(int)k;++i)
#define per(i,j,k) for(int i=(int)j;i>(int)k;--i)
#define lowbit(a) a&-a
#define Max(a,b) a>b?a:b
#define Min(a,b) a>b?b:a
#define mem(a,b) memset(a,b,sizeof(a))

typedef long long LL;
typedef unsigned long long LLU;
typedef double db;
const int N=1e5+10;
const int inf=0x3f3f3f3f;

char str[N];
bool vis[N];

int dir4[4][2]= {{1,0},{0,1},{-1,0},{0,-1}};
int dir8[8][2]= {{1,0},{1,1},{0,1},{-1,1},{-1,0},{-1,-1},{0,-1},{1,-1}};
int movv[5][2]= {{1,0},{0,1},{0,0},{-1,0},{0,-1}};

inline LL read()
{
    int c=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();}
    return c*f;
}
__int64  t,n,m,p,q,u,v;
int len;
char s1[N];
char s2[N];
int ok;

struct graph
{
    int mat[2];
} g[N];

vector<int>V[N];
int vec;

void dfs(int u,int k)
{
    vis[u]=true;
    g[vec].mat[k]++;
    for(int i=0; i<V[u].size(); i++){
        int v=V[u][i];
        if (!vis[v])
            dfs(v,k^1);
    }
}

bool cmp(const graph &x,const graph &y)
{
    return x.mat[0]-x.mat[1] > y.mat[0]-y.mat[1];
}

int main()
{
    t=read();
    while(t--){
        scanf("%I64d%I64d",&n,&m);
        for(int i=1; i<=n; i++){
            V[i].clear();
            vis[i]=0;
        }
        for(int i=1; i<=m; i++){
            u=read();
            v=read();
            V[u].push_back(v);
            V[v].push_back(u);
        }
        vec=0;
        for(int i=1; i<=n; i++){
            if (!vis[i]){
                g[vec].mat[0]=g[vec].mat[1]=0;
                dfs(i,0);
                vec++;
            }
        }
        for(int i=0; i<vec; i++){
            if (g[i].mat[0]<g[i].mat[1])
                swap(g[i].mat[0],g[i].mat[1]);
        }
        sort(g,g+vec,cmp);
        __int64 x=0,y=0;
        for (int i=0; i<vec; i++){
            if(x>y) swap(x,y);
            x+=g[i].mat[0];
            y+=g[i].mat[1];
        }
        printf("%I64d\n",x*y-m);
    }
    return 0;
}


你可能感兴趣的:(比赛,BestCoder)