Souvenir



问题描述



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

今天总共有n个参赛者, Soda想要知道最少需要花多少钱才可以给每个人都准备一个纪念品.



输入描述



输入有多组数据. 第一行有一个整数T (1≤T≤105), 表示测试数据组数. 然后对于每组数据:

一行包含4个整数 n,m,p,q (1≤n,m,p,q≤104).



输出描述



对于每组数据输出最小花费.



输入样例



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. 1≤l1≤r1<l2≤r2<l3≤r3≤n

2. s[l1..r1], s[l2..r2], s[l3..r3]依次连接之后得到字符串"anniversary".


输入描述


输入有多组数据. 第一行有一个整数T (1≤T≤100), 表示测试数据组数. 然后对于每组数据:

一行包含一个仅含小写字母的字符串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 (n≥1)项是3n(n−1)+1. 现在他想知道对于一个给定的整数m, 是否可以表示成若干项上述数列的和. 如果可以, 那么需要的最小项数是多少?

例如, 22可以表示为7+7+7+1, 也可以表示为19+1+1+1.


输入描述


输入有多组数据. 第一行有一个整数T (1≤T≤104), 表示测试数据组数. 然后对于每组数据:

一行包含1个整数 m (1≤m≤109).


输出描述


对于每组数据输出最小花费.


输入样例


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 (1≤T≤100), 表示测试数据组数. 然后对于每组数据:

第一行报包含两个整数n和m, (2≤n≤10000,0≤m≤100000).

接下来m行, 每行两个整数u和v(1≤u,v≤n,v≠u), 表示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=dpi−1,x−a[i] or dpi−1,x−b[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;
}