菜就要多補題。。
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);
}
}