菜就要多补题。。
A 大仙买贡茶
题目大意:
现在有有n杯偶数价格的贡茶,每两杯贡茶将会选择其中价格最低的贡茶进行半价,问最少花多少钱可以买完所有贡茶。
题解:
水题。sort一下。每次两位两位挪动,第二位的减半即可。
/*
@resources: BNUZCPC A
@date: 2017-5-14
@author: QuanQqqqq
@algorithm: yy
*/
#include <bits/stdc++.h>
#define MAXN 1005
using namespace std;
int num[MAXN];
int main(){
int T,n,cas = 1;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
int ans = 0;
for(int i = 0;i < n;i++){
scanf("%d",&num[i]);
ans += num[i];
}
sort(num,num + n);
for(int i = n - 1;i >= 1;i -= 2){
ans -= num[i - 1] / 2;
}
printf("Case #%d: %d\n",cas++,ans);
}
}
B 丽泽湖毒素
题目大意:
交互式判题,每次机器先告诉你有m瓶酒,然后要你限定在10只老鼠的情况下,告诉机器应该让他们如何喝酒,然后机器会告诉你有多少只老鼠死了和他们的编号,最后你要告诉机器,答案是什么。
题解:
10只老鼠,2的10次方是1024,可以用二进制表示来模拟老鼠喝酒,先告诉机器n批老鼠,第i批所使用的老鼠是i的二进制数所对应的位置,最终得到死亡的老鼠再转回10进制就是所需的答案。
比赛的时候wa在空格上orz。。。
/*
@resources: BNUZCPC B
@date: 2017-5-14
@author: QuanQqqqq
@algorithm: yy
*/
#include <bits/stdc++.h>
using namespace std;
int main(){
string str;
int n;
while(cin >> n >> str >> str >> str){
for(int i = 1;i <= n;i++){
int p = i;
int total = 0;
while(p){
if(p & 1){
total++;
}
p >>= 1;
}
printf("%d",total);
fflush(stdout);
int tmp = i,idx = 1;
while(tmp){
if(tmp & 1){
printf(" %d",idx);
fflush(stdout);
}
idx++;
tmp >>= 1;
}
printf("\n");
fflush(stdout);
}
int tmp;
int ans = 0;
cin >> n >> str >> str;
for(int i = 0;i < n;i++){
cin >> tmp;
ans |= (1 << (tmp - 1));
}
printf("%d\n",ans);
fflush(stdout);
}
}
C 网络支付的回调通知系统
很繁杂的一道模拟题,用优先队列模拟,队友赛后强撸补完了。。晚点补。
队友的代码:
#include<bits/stdc++.h>
#include<time.h>
#define ll long long
using namespace std;
struct data{
string post;
ll getTime,sendTime;
int fashi;
bool operator < (const data &a) const {
if(sendTime != a.sendTime) return sendTime>a.sendTime;
else return getTime>a.getTime;
}
}packet;
priority_queue<data> all,que;
vector<data> ans;
map<ll,bool> stop;
char ret[105];
int plu[6] = {10,60,1800,7200,43200,86400};
ll getTime(char* str){
struct tm stm;
memset(&stm,0,sizeof(stm));
ll year = 0,month = 0,day=0,hour=0,m=0,s=0;
for(int i = 0;i < 4;i++)
year = year * 10 + str[i] - '0';
for(int i = 5;i < 7;i++)
month = month * 10 + str[i] - '0';
for(int i = 8;i < 10;i++)
day = day * 10 + str[i] - '0';
for(int i = 11;i < 13;i++)
hour = hour * 10 + str[i] - '0';
for(int i = 14;i < 16;i++)
m = m * 10 + str[i] - '0';
for(int i = 17;i < 19;i++)
s = s * 10 + str[i] - '0';
stm.tm_year=year-1900;
stm.tm_mon=month-1;
stm.tm_mday=day;
stm.tm_hour=hour + 8;
stm.tm_min=m;
stm.tm_sec=s;
return mktime(&stm);
}
void getNewTime(ll data){
struct tm *p;
time_t t = data;
p=gmtime(&t);
strftime(ret, sizeof(ret), "%Y-%m-%d %H:%M:%S", p);
}
int main(){
int T,q;
char str[1000000],tmp[1000000];
scanf("%d",&T);
while(T--){
stop.clear();
while(!all.empty()) all.pop();
while(!que.empty()) que.pop();
int n;
scanf("%d",&n);
getchar();
for(int i = 0;i < n;i++){
gets(str);
packet.post = str;
for(int j = 13;j < 32;j++) tmp[j - 13] = str[j];
tmp[32] = '\0';
packet.getTime = packet.sendTime = getTime(tmp);
packet.fashi = 0;
all.push(packet);
}
int m;
scanf("%d",&m);
getchar();
for(int i = 0;i < m;i++){
gets(str);
stop[getTime(str)] = true;
}
scanf("%d",&q);
getchar();
while(q--){
ans.clear();
int len = 0;
gets(str);
ll now = getTime(str);
while(!all.empty()){
data temp = all.top();
if(temp.sendTime > now) break;
all.pop();
que.push(temp);
}
while(!que.empty()){
data temp = que.top();
if(temp.sendTime >= now) break;
que.pop();
if(!stop[temp.sendTime]) continue;
if(temp.fashi >= 5){
temp.sendTime += plu[5];
}else{
temp.sendTime += plu[temp.fashi++];
}
que.push(temp);
}
while(!que.empty()){
ans.push_back(que.top());
que.pop();
len++;
if(len == 100) break;
}
for(int i = 0;i < len;i++){
getNewTime(ans[i].sendTime);
cout<<ans[i].post;
printf(",%s\n",ret);
que.push(ans[i]);
}
}
}
}
/*
1
8
{"datetime":"2014-06-15 08:37:18","callbackurl":"abc.com"}
{"datetime":"2014-06-15 08:37:19","callbackurl":"abc.com"}
{"datetime":"2014-06-15 08:37:20","callbackurl":"ab.com"}
{"datetime":"2014-06-15 08:37:21","callbackurl":"a.com"}
{"datetime":"2014-06-15 08:37:22","callbackurl":"abc.com"}
{"datetime":"2014-06-15 08:37:23","callbackurl":"ac.com"}
{"datetime":"2014-06-15 08:37:31","callbackurl":"ac.com"}
{"datetime":"2014-06-15 08:37:33","callbackurl":"acm.com"}
4
2014-06-15 08:37:18
2014-06-15 08:37:20
2014-06-15 08:37:21
2014-06-15 08:37:28
3
2014-06-15 08:37:18
2014-06-15 08:37:20
2014-06-15 08:37:29
*/
D 第一章:异世界修仙
题目:
有n个点,如果满足强联通性(就是可以从i点到j点且可以从j点到i点),则他们可以算作一个群。
现在问最少花费多少可以使所有点都给打通,群内只要有一个点被打通了,所有点都被打通。
并求方案数。
题解:
一个很裸的Tarjan算法。。判断强联通之后,在强联通的图中,找到最小花费和最小花费的方案数,然后两两群的方案数相乘,两两群最小花费相加即可。
代码:
/*
@resources: BNUZCPC D
@date: 2017-5-16
@author: QuanQqqqq
@algorithm: tarjan
*/
#include <bits/stdc++.h>
#define MAXN 100005
#define ll long long
#define INF 0x3f3f3f
#define MOD 1000000007
using namespace std;
struct node{
ll col,tot;
}color[MAXN];;
bool vis[MAXN];
vector<int> vs[MAXN];
int low[MAXN],dfn[MAXN];
stack<int> s;
int idx,col_num,col_t;
ll c[MAXN];
void Tarjan(int v){
dfn[v] = low[v] = idx++;
vis[v] = true;
s.push(v);
for(int i = 0;i < vs[v].size();i++){
if(!dfn[vs[v][i]]){
Tarjan(vs[v][i]);
low[v] = min(low[v],low[vs[v][i]]);
} else if(vis[vs[v][i]]) {
low[v] = min(low[v],dfn[vs[v][i]]);
}
}
if(dfn[v] == low[v]){
vis[v] = false;
ll maxt = c[v];
ll tot = 0;
while(!s.empty()){
if(s.top() != v){
if(maxt > c[s.top()]){
tot = 0;
maxt = c[s.top()];
}
if(maxt == c[s.top()]){
tot++;
}
vis[s.top()] = false;
s.pop();
} else {
break;
}
}
if(maxt == c[s.top()]){
tot++;
}
color[col_t].col = maxt;
color[col_t].tot = tot;
col_t++;
s.pop();
}
}
void addEdge(int u,int v){
vs[u].push_back(v);
}
void init(){
idx = col_num = 1;
col_t = 0;
while(!s.empty()){
s.pop();
}
for(int i = 0;i < MAXN;i++){
vs[i].clear();
}
memset(color,0,sizeof(color));
memset(low,0,sizeof(low));
memset(dfn,0,sizeof(dfn));
}
int main(){
int T,cas = 1,n,m,v,u;
scanf("%d",&T);
while(T--){
init();
scanf("%d",&n);
for(int i = 1;i <= n;i++){
scanf("%lld",&c[i]);
}
scanf("%d",&m);
while(m--){
scanf("%d %d",&u,&v);
addEdge(u,v);
}
for(int i = 1;i <= n;i++){
if(!dfn[i]){
Tarjan(i);
}
}
ll ans1 = 0,ans2 = 1;
for(int i = 0;i < col_t;i++){
ans1 += color[i].col;
ans2 = (ans2 * color[i].tot) % MOD;
}
printf("Case #%d: %lld %lld\n",cas++,ans1,ans2);
}
}
E Enigma Pro
题目:
一个编码器,按照题目模拟,三个转盘,每次需要先经过配线版,再经过三个转盘,在经过反射器,再反向经过三个转盘,再经过配线版。。
题解:
按照题目模拟即可。只是,样例那很容易wa,因为,他的字母是按顺序的。。。
反向的时候要特别注意,对应的是哪个字符,唯一坑点。
代码:
/*
@resources: BNUZCPC E
@date: 2017-5-16
@author: QuanQqqqq
@algorithm: 模拟
*/
#include <bits/stdc++.h>
#define MAXN 30
using namespace std;
char mapp[200];
char zp[10][MAXN];
char ban[200];
char fz[10][200];
char str[2005];
int m,z1,z2,z3,s1,s2,s3;
void zhuan(){
s1++;
if(s1 == 26){
s1 = 0;
s2++;
}
if(s2 == 26){
s2 = 0;
s3++;
}
if(s3 == 26){
s3 = 0;
}
}
char encode(char c){
if(ban[c] != -1){
c = ban[c];
}
c = zp[z1][(c - 'a' + s1) % 26];
c = zp[z2][(c - 'a' + s2) % 26];
c = zp[z3][(c - 'a' + s3) % 26];
c = mapp[c];
c = zp[z3][fz[z3][(fz[z3][c] - s3 + 26) % 26 + 'a']];
c = zp[z2][fz[z2][(fz[z2][c] - s2 + 26) % 26 + 'a']];
c = zp[z1][fz[z1][(fz[z1][c] - s1 + 26) % 26 + 'a']];
if(ban[c] != -1){
c = ban[c];
}
zhuan();
return c;
}
int main(){
int T,cas = 1;
char a,b;
scanf("%d",&T);
getchar();
while(T--){
memset(mapp,0,sizeof(mapp));
memset(zp,0,sizeof(zp));
memset(fz,0,sizeof(fz));
memset(ban,-1,sizeof(ban));
for(int i = 0;i < 13;i++){
scanf("%c %c",&a,&b);
getchar();
mapp[a] = b;
mapp[b] = a;
}
scanf("%d",&m);
getchar();
for(int i = 1;i <= m;i++){
for(int j = 0;j < 26;j++){
scanf("%c",&zp[i][j]);
fz[i][zp[i][j]] = j;
getchar();
}
}
scanf("%d %d %d",&z1,&z2,&z3);
scanf("%d %d %d",&s1,&s2,&s3);
int tmp1 = s1,tmp2 = s2,tmp3 = s3;
scanf("%d",&m);
getchar();
while(m--){
scanf("%c %c",&a,&b);
getchar();
ban[a] = b;
ban[b] = a;
}
scanf("%d",&m);
getchar();
printf("Case #%d:\n",cas++);
while(m--){
gets(str);
int len = strlen(str);
for(int i = 0;i < len;i++){
if(str[i] == ' '){
printf(" ");
} else {
printf("%c",encode(str[i]));
}
}
printf("\n");
s1 = tmp1,s2 = tmp2,s3 = tmp3;
}
}
}
F 华农酸奶配方
题意:
给一个有序的数,需要找出里面一个区间内满足排序后连续的方案数。
题解:
orz某大牛学长留的防ak题。时间复杂度硬卡到O(n)。单调栈+并查集。
只能想到用线段树维护O(nlogn)的算法。
每次进入一个数,维护这个线段树该区间的最大值,最小值,区间和。
如果满足maxn * (maxn + 1) / 2 - minn * (minn + 1) / 2 == total 且 r - l = maxn - minn就可以统计方案数。
多的不讲了。。反正菜,写不出来。
G 凤凰山下的缆车与电瓶车
题意:
1.某号缆车或某号电瓶车单程票,耗费c1块钱
2.不限次数的某号缆车或某号电瓶车票,耗费c2块钱
3.不限次数的所有缆车或电瓶车票,耗费c3块钱
4.不限次数的所有缆车和电瓶车票,耗费c4块钱
现在知道缆车n个编号和电瓶车m个编号,和某学生乘坐交通工具的详细情况,请你找出该学生需要花费的最小金钱。
题解:
水题。累加上来之后每一层对比就可以了。
/*
@resources: BNUZCPC G
@date: 2017-5-14
@author: QuanQqqqq
@algorithm: yy
*/
#include <bits/stdc++.h>
#define MAXN 1005
using namespace std;
int main(){
int T,cas = 1,c1,c2,c3,c4,n,m,tmp,m1,m2;
scanf("%d",&T);
while(T--){
scanf("%d %d %d %d %d %d",&c1,&c2,&c3,&c4,&n,&m);
m1 = m2 = 0;
for(int i = 0;i < n;i++){
scanf("%d",&tmp);
m1 += min(tmp * c1,c2);
}
for(int i = 0;i < m;i++){
scanf("%d",&tmp);
m2 += min(tmp * c1,c2);
}
printf("Case #%d: %d\n",cas++,min(c4,min(m1,c3) + min(m2,c3)));
}
}
H 奖学金战争
题意:
两个人玩游戏,钱多的那个人(a)要给钱少的那个人(b),b拥有的钱的数量。问最终能否平分
题解:
如果,有一个人的钱为0(且两个不全为0)肯定是No,如果相加是奇数肯定是No。
如果相加之后的数,除去尾0(比赛的时候死wa这里。。最后都没找出来)。如果是2^n,就一定是Yes。
否则,模拟一下相加的数,一直除2,看看a和b是否有在这个数里出现过,如果出现了就是Yes。
代码:
/*
@resources: BNUZCPC H
@date: 2017-5-14
@author: QuanQqqqq
@algorithm: yy
*/
#include <bits/stdc++.h>
#define ll long long
using namespace std;
bool check(ll n){
while(n){
if(n != 1 && (n & 1)){
return false;
}
n >>= 1;
}
return true;
}
int main(){
int T,cas = 1;
ll n,m;
scanf("%d",&T);
while(T--){
scanf("%lld %lld",&n,&m);
printf("Case #%d: ",cas++);
if(n == m){
puts("Yes");
continue;
} else if(n == 0 || m == 0 || (n + m) % 2){
puts("No");
continue;
}
while(n % 10 == 0 && m % 10 == 0){
n /= 10;
m /= 10;
}
ll sum = n + m;
if(check(sum)){
puts("Yes");
continue;
}
if(n > m){
swap(n,m);
}
while(sum){
if(sum == n){
puts("Yes");
break;
}
if(sum % 2){
puts("No");
break;
}
sum /= 2;
}
}
}
I 厉害了我的Q
题目:
小Q(菜鸡)要从(0,0,0)点开始走到题目给出的各个点,途中还能向上飞向下飞(不能遁地),最终要走到(a,b,0)这个点。问方案数有多少。
题解:
其实可以分位置来考虑。
水平和竖直的其实不会影响的。(比赛时以为会影响。。想出了一个O(n^3)妥妥的放弃了)
对于水平方向,有dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
对于竖直方向,有dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j] + dp[i - 1][j + 1]
然后最终点直接相乘即可。竖直方向的数是一个默慈金数,水平方向的明显打表。
这里要注意。。竖直方向如果在线算的话,时间复杂度是不够的。因为n个点的情况下再算上3000 * 1500 是妥妥超时的,默慈金数是可以打表的。所以两个都离线打表就好了。竖直方向的i代表要走的步数,所以应该是3001为最大。
代码:
/*
@resources: BNUZCPC I
@date: 2017-5-16
@author: QuanQqqqq
@algorithm: math
*/
#include <bits/stdc++.h>
#define MAXN 1505
#define MOD 1000000007
#define ll long long
using namespace std;
ll level[MAXN][MAXN];
ll height[MAXN * 2][MAXN];
struct point{
ll x,y;
point(ll _x,ll _y) : x(_x),y(_y){}
point(){}
};
point a[MAXN],tmp;
ll myAbs(ll a){
return a > 0 ? a : -a;
}
void init(){
level[1][1] = height[1][1] = 1;
for(ll i = 1;i < MAXN;i++){
for(ll j = 1;j < MAXN;j++){
if(i == 1 && j == 1){
continue;
}
if(i >= 2){
level[i][j] += level[i - 1][j];
}
if(j >= 2){
level[i][j] += level[i][j - 1];
}
level[i][j] %= MOD;
}
}
for(ll i = 2;i < MAXN * 2;i++){
for(ll j = 1;j <= i && j < MAXN - 1;j++){
height[i][j] = (height[i - 1][j - 1] + height[i - 1][j] + height[i - 1][j + 1]) % MOD;
}
}
}
ll getLen(point a,point b){
return myAbs(a.x - b.x) + myAbs(a.y - b.y);
}
int main(){
init();
ll T,n,cas = 1;
scanf("%lld",&T);
while(T--){
scanf("%lld",&n);
ll ans = 1;
a[0] = point(0,0);
for(ll i = 1;i <= n;i++){
scanf("%lld %lld",&a[i].x,&a[i].y);
tmp = point(myAbs(a[i].x - a[i - 1].x) + 1,myAbs(a[i].y - a[i - 1].y) + 1);
ans = (ans * ((height[getLen(a[i],a[i - 1]) + 1][1] * level[tmp.x][tmp.y]) % MOD)) % MOD;
}
printf("Case #%lld: %lld\n",cas++,ans);
}
}