感觉翻译有误差不便于理解直接用原题目了
解题报告-2020-3-21周六,12:00~17:00,ICPC训练联盟周赛,Benelux Algorithm Programming Contest 2019。
Benelux Algorithm Programming Contest,BAPC
A题目Appeal to the Audience
A Appeal to the Audience
Time limit: 1s
You are the director of the upcoming Bordfite Arena
Progaming Competition. You have invited a bunch
of players and are now setting up the matches for the
knockout tournament that will determine the winner.
As you may know, Bordfite Arena is a game that heav-
ily rewards skill and very little luck is involved. This
implies that whenever any number of players play a game of Bordfite Arena, the most skilled
player will always win! Hence the winner of the tournament is already known, and you are a
bit worried about this. How will you appease the audience?
You embark on a short quest to find out what the audience finds interesting. No surprises
there: people find it most interesting when they see skillful players compete. Whenever a
match is played, the happiness the audience gets from a match is the sum of the skill levels
of the players. The total happiness the audience gets from the tournament is the sum of the
happiness obtained during all matches. This is very useful information, because of course you
want the audience to be as happy as possible at the end of the tournament.
Moreover, you invested some time to ask people what kind of knockout format they like. It
turns out that instead of the plain old binary tree for the knockout schedule, they prefer a
specific weird-looking rooted tree, and so you decide to use that. This means the final step
for you to complete is to divide the players over the leaves of the given tree so that over the
entire tournament, the happiness of the audience is maximized.
Input
• The first line contains integers 3 ≤ n ≤ 10 5 and 1 ≤ k ≤ n − 1, the number of nodes of
the tree and the number of players. The nodes are labelled 0 through n − 1, and 0 is
the root of the tree.
• The second line contains k integers 0 ≤ a 1 ,...,a k ≤ 10 9 , denoting the skill values of
the players.
• Then follow n − 1 lines, the ith of which (1 ≤ i ≤ n − 1) contains the parent 0 ≤ p i < i
of node i.
It is guaranteed that the tree has exactly k leaves and that there are no nodes with exactly
one child.
Output
• Output the maximal possible happiness the audience can obtain from this tournament.
4 Problem A: Appeal to the Audience
Sample Input 1 Sample Output 1
5 3
5 4 3
0
0
1
1
17
Sample Input 2 Sample Output 2
11 7
30 5 15 1 3 100 50
0
0
1
0
2
5
2
5
5
1
454
要想使得总和最大,就要使最大值被计算的次数最多。要想某个数被计算的多,就要使得它经过尽量多
的节点。于是我们的目标就是找到 k 条从长到短的链,这些链互不重合,且一端是叶子节点。
可以通过长链剖分来将这棵树分为 k 条互不相交的长链,然后按照长度分配元素(长度越大,分配给它
的元素值越大)。
代码(原题解代码)
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
const int M = N<<1;
typedef long long ll;
/* 邻接表代码 */
int head[N],nex[M],ver[M],tot = 1;
void addEdge(int x,int y){
ver[++tot] = y; nex[tot] = head[x]; head[x] = tot;
}
/* 快读代码 */
int getInt(){
int res = 0;
bool neg = false;
char c = getchar();
while(c != '-' && (c > '9' || c < '0')) c = getchar();
if(c == '-') neg = true, c = getchar();
while(c >= '0' && c <= '9') res = res*10+c-'0',c = getchar();
return neg?-res:res;
}
int len[N],son[N],top[N];
//依次为当前子树最大深度、重儿子编号、当前链顶节点编号
void dfs(int x){
for(int i = head[x];i;i = nex[i]){
dfs(ver[i]);
if(len[son[x]] < len[ver[i]]) son[x] = ver[i];
}
len[x] = len[son[x]]+1;
for(int i = head[x];i ;i = nex[i]){//也可以不更新top数组,在此直接压入q1
if(ver[i] == son[x]) top[son[x]] = top[x];
else top[ver[i]] = ver[i];
}
}
int n,k,a[N];
ll ans = 0;
priority_queue<ll> q1,q2;
void solve(){
top[1] = 1; dfs(1);
for(int i = 2;i <= n;i++)
if(top[i] == i) q1.push(len[i]);
q1.push(len[1]-1);
while(q1.size()){
ans += 1ll * q1.top() * q2.top();
q1.pop(); q2.pop();
}
printf("%lld\n",ans);
}
int main(){
n = getInt(); k = getInt();
for(int i = 1,x;i <= k;i++) x = getInt(),q2.push(x);
for(int i = 2,y;i <= n;i++) y = getInt(), addEdge(y+1,i);
solve();
return 0;
}
感想
对二叉树还有节点的知识了解不多,需要加强练习
B题目
B Breaking Branches Time limit: 1s
CC-BY 2.0 By DymphieH on
Flickr
Your parents decided that it would be “fun” to spend the entire
Sunday walking near the Mookerheide close to Nijmegen.
Although you can pass the time by solving programming problems
in your head, your siblings do not have the same luxury. After a
short while, your younger sister Alice and your big brother Bob
find themselves hopelessly bored. Together, they try to figure out
if they can pass the time with a game (a problem that would later
be referred to as the Bob and Alice Pastime Conundrum). Finally,
they come up with the following simple game.
They find a single branch of length n that will be the main object of the game. Alternatingly,
Alice and Bob choose a piece of branch and break it into two parts, in such a way that both
parts have integer lengths. The last player who is able to break one of the pieces wins. Alice
gets to start, as she is the younger of the two.
Of course, you already have the game figured out in your head. Assuming Bob plays optimally,
can Alice win the game? And if so, what move should she make first?
Input
• A line containing a single integer 2 ≤ n ≤ 10 9 , the length of the branch.
Output
• On the first line print the name of the person who wins, Alice or Bob.
• If Alice can win, print the length of a piece of branch Alice can break off as a winning
move. This should be an integer between 1 and n − 1, inclusive.
If there are multiple valid solutions, you may output any one of them.
Sample Input 1 Sample Output 1
2 Alice
1
Sample Input 2 Sample Output 2
3 Bob
代码(原题解代码)
#include<bits/stdc++.h>
using namespace std;
int n;
int main(){
cin >> n;
if(n&1) cout << "Bob" << endl;
else cout << "Alice\n1" << endl;
return 0;
}
感想
/*当 n = 1,n = 2 时已知结论成立。
如果对于 n <= 2k 结论都成立,
那么对于 n = 2k+1,必然要分为奇数+偶数,
所以 n = 2k+1 必然要分为 N 态 + P 态,即 n = 2k+1 为 N 态。(博弈论有向图游戏)
同理,对于 n = 2k+2,可以将其分为任意两个奇数的和,使其分为 N 态 + N 态,从而 n = 2k+2 为 P
态。
故 n = 2k+1 , n = 2k+2 时结论成立。
综上所述,若 n 为奇数,则先手必败,若 n 为偶数,则先手必胜。*/
自己打时直接判断的是否为偶数,偶数则是女孩,奇数则男孩。有一定的规律,情况有多种正确即可。
C题目
C Conveyor Belts Time limit: 1s
You are an employee of the Boxing And Processing Com-
pany and you are tasked with distributing boxes in one
of the company’s enormous warehouses. At BAPC Ltd.,
boxes travel by conveyor belt. Two conveyor belts can be
merged into one by letting one drop its content onto the
other. On the other hand, a belt can be split into two by
using a splitter, which sends a specific portion of its input
to its first output and the rest to its second output. Nor-
mally your splitters are adjustable, being able to distribute
its input over its output belts in any conceivable ratio, but in an attempt to cut costs your
boss has ordered cheap knock-off splitters which can only distribute its input in a fixed ratio
a : b. Instead of arguing with your boss about how you really need some c : d splitters, you
decide to make them yourself.
Of course, with your frugal boss, you have to watch your costs. You cannot build your
splitter system in such a way that there are boxes that never leave the system. Nor can you
use splitters that never receive any boxes. Finally, you cannot use too many a : b splitters in
total.
Given the ratios a : b and c : d, construct a network of belts and at most 200 knock-off a : b
splitters that has a single global input belt and two global output belts over which the global
input is distributed in a ratio c : d.
Note that a splitter of ratio x : y sends exactly
x
x+y
of the incoming boxes to the first output
and exactly
y
x+y
of them to the second output.
Input
• The first line contains two integers 1 ≤ a,b ≤ 10 9 with a + b ≤ 10 9 denoting the ratio
a : b of your knock-off splitter.
• The second line contains two integers 1 ≤ c,d ≤ 10 9 with c+d ≤ 10 9 denoting the ratio
c : d of your desired splitter.
Output
• The first line contains an integer 1 ≤ n ≤ 200, the number of a : b splitters used.
• Then follow n lines, the i-th of which contains two integers −2 ≤ l i ,r i < n.
Here l i is the index of the splitter connected to the left output of the i-th splitter, where it
deposits a/(a + b) of its input. Similarly r i is the index of the splitter receiving b/(a + b) of
the input of the i-th splitter. The splitters are indexed starting from 0. The global input is
connected to splitter 0. The special values −1 and −2 for l i and r i correspond to the first
8 Problem C: Conveyor Belts
and second global output, which need to receive c/(c + d) and d/(c + d) of the global input
respectively.
Note that you cannot place a splitter in such a way that no box ever reaches it, nor in such
a way that a box that passes through it will never reach the output.
If there are multiple possible solutions, you may output any one of them.
Sample Input 1 Sample Output 1
2 3
3 2
1
-2 -1
Sample Input 2 Sample Output 2
1 2
3 4
3
-1 1
2 1
0 -2
Sample Input 3 Sample Output 3
1 2
1 2
3
-2 1
2 0
1 -1
代码(原题解代码)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a,b,c,d,n;
void Connect(int p,int l,int r){
/* 将第 p 个 1:1 的分割器左边与第 l 个,右边与第 r 个相连 */
printf("%d %d\n",p*3+1, p*3+2);
printf("%d %d\n",p*3, l>0?l*3:l);
printf("%d %d\n",r>0?r*3:r, p*3);
}
void solve(){
/* 大体将点分为三层:二进制层(1,2,4,..), 二进制层(这层每个二进制可用两次),
答案层:即k+cnt,k+cnt1 , 它们是用来存放答案的 */
int low,high,flag = 0,cnt = 0;
if(c > d) swap(c,d),flag = true; //确保 c < d
for(int i = 0;i <= 31;i++) if((c>>i)&1 || (d>>i)&1) cnt++;//统计需要多少二
进制位
for(low = 0;low <= 31;low++) //统计最低位与最高位,浪费可耻
if(((d>>low)&1) || ((c>>low)&1)) break;
for(high = 31;high >= low;high--) if((d>>high)&1) break;
int k = high - low + 1,fp = cnt;//fp为临时指针
printf("%d\n",(k+cnt+2)*3);
for(int i = 0;i < k;i++){
int p = high - i,rs = (i==k-1)?0:i+1;
if((c>>p)&1 || (d>>p)&1) Connect(i,k+(--fp),rs);
else Connect(i,0,rs);
}
for(int i = 0;i <= 31;i++){
if((c>>i)&1 && (d>>i)&1) Connect(k+(fp++),k+cnt,k+cnt+1);
else if((c>>i)&1) Connect(k+(fp++),k+cnt,0);
else if((d>>i)&1) Connect(k+(fp++),0,k+cnt+1);
}
Connect(k+cnt,flag?-2:-1,0); Connect(k+cnt+1,flag?-1:-2,0);//输出答案
}
int main(){
scanf("%d%d%d%d",&a,&b,&c,&d);
solve();
return 0;
}
感想
没能理解题意,直接跳过后没来得及做,后来参考题解有了部分了解,但是对题解方法还是不会应用。
D题目
D Deck Randomisation Time limit: 1s
CC-BY-SA 4.0 By Alexey Musulev on
wikimedia.org
Alice and Bob love playing Don’tminion, which typically
involves a lot of shuffling of decks of different sizes. Because
they play so often, they are not only very quick at shuffling,
but also very consistent. Each time Alice shuffles her deck,
her cards get permuted in the same way, just like Bob
always permutes his cards the same way when he shuffles
them. This isn’t good for playing games, but raises an
interesting question.
They know that if they take turns shuffling, then at some
point the deck will end up ordered in the same way as when they started. Alice shuffles once
first, then Bob shuffles once, then Alice shuffles again, et cetera. They start with a sorted
deck. What they do not know, however, is how many shuffles it will take before the deck is
sorted again.
Can you help them compute how many shuffles it will take? As Alice and Bob can only do
10 12 shuffles in the limited time they have, any number strictly larger than this should be
returned as huge instead.
Input
• The first line contains a single integer 1 ≤ n ≤ 10 5 , the number of cards in the deck.
• The second line contains n distinct integers 1 ≤ a 1 ,a 2 ,...,a n ≤ n, where a i is the new
position of the card previously at position i when Alice shuffles the deck.
• The third line contains n distinct integers 1 ≤ b 1 ,b 2 ,...,b n ≤ n, where b i is the new
position of the card previously at position i when Bob shuffles the deck.
Output
• Output a single positive integer m > 0, the minimal number of shuffles required to sort
the deck, or huge when this number is strictly larger than 10 12 .
Sample Input 1 Sample Output 1
3
2 3 1
3 1 2
2
Sample Input 2 Sample Output 2
6
5 1 6 3 2 4
4 6 5 1 3 2
5
10 Problem D: Deck Randomisation
Sample Input 3 Sample Output 3
8
1 4 2 6 7 8 5 3
3 6 8 4 7 1 5 2
10
代码(原题解代码)
#include <cstdio>
#include <algorithm>
#include <vector>
#define LL long long
#define ll __int128
const int N = 1e5 + 7;
const LL LIM = 1e12;
int n,cnt_vv=0,num = 0;
LL a[N],b[N],ab[N],ba[N],at[N];
ll p[N],r[N],ans1,ans2,ans,pt;
bool bk[N];
std::vector<ll> vv[N];
inline void print(ll x){
if(x<0){
putchar('-');
x=-x;
}
if(x>9)
print(x/10);
putchar(x%10+'0');
}
ll gcd(ll a, ll b){
return b ? gcd(b,a%b) : a;
}
ll lcm(ll a,ll b){
return a/gcd(a,b)*b;
}
ll exgcd(ll a,ll b,ll &x, ll &y){
if(b == 0){
x = 1;
y = 0;
return a;
}
ll t = exgcd(b,a%b,x,y);
ll x0 = x,y0 = y;
x = y0;
y = x0-a/b*y0;
return t;
}
ll even(){
ll res = 1;
cnt_vv = 0;
for(int i = 1; i <= n; ++i){
int t = i;
if(bk[t]) continue;
int l = 0;
while(!bk[t]){
bk[t] = true;
vv[cnt_vv].push_back(t);
l++;
t = ab[t];
}
++cnt_vv;
res = lcm(res,l);
if(res > LIM) return LIM+1;
}
return res;
}
bool odd(){
bool flag = 1;
for(int i = 0 ; i < cnt_vv; ++i){
int size = vv[i].size();
for(int j = 0; j < size; ++j){
flag = 1;
for(int k = 0; k < size; k++){
if(at[vv[i][k]] != vv[i][(j+k)%size]){
E Efficient Exchange
flag = 0;
break;
}
}
if(flag){
p[++num] = size;
r[num] = j%size;
break;
}
}
if(!flag) break;
}
return flag;
}
ll CRT(){
bool flag = 0;
ll x,y,g,x0,rt;
pt = p[1],rt = r[1];
for(int i = 2;i <= num; ++i){
g = exgcd(pt,p[i],x,y);
if((r[i] - rt) % g){
flag = 1;
}else{
x0 = (r[i]-rt) / g * x % (p[i]/g);
rt = x0*pt + rt;
pt = pt / g * p[i];
}
rt = (rt % pt + pt) % pt;
}
if(flag) return LIM+1;
else return rt;
}
int main(){
scanf("%d",&n);
for(int i = 1; i <= n; ++i) scanf("%lld",a+i),at[a[i]] = i;
for(int i = 1; i <= n; ++i) scanf("%lld",b+i);
for(int i = 1; i <= n; ++i) ab[i] = a[b[i]];
ans1 = even();
if(odd()){
ans2 = CRT();
ans1 *= 2;
ans2 = ans2 * 2 +1;
ans = ans1;
if(ans > ans2) ans = ans2;
}else{
ans1 *= 2;
ans = ans1;
}
if(ans > LIM) puts("huge");
else print(ans);
return 0;
}
感想
没做完。后来自己又打了一次代码但是跟题解相比,自己漏了很多条件,而且套了三个for循环,会超时,于是用的题解代码,题解写的函数感觉很实用。
/*置换循环节+扩展中国剩余定理
置换可以表示成num个循环节乘积的形式,我们求出第 i 个循环节的循环长度 p[i] 和第 i 个循环节第一
次变成目标顺序的置换次数 r[i]. 可以解释为:
第 i 个循环节经过了 ki * p[i] + r[i] 次的置换可以变成目标顺序。
我们可以得到一个有 num 个同余方程的同余方程组,因为 p[i] 可能并非两两互质,所以要使用扩展中
国剩余定理来解同余方程组;
因为Alice和Bob是轮流刷牌,目标状态可能是在A达到的,也可能是在B达到。所以本题分奇偶;
1. 偶数情况(A和B刷牌次数一样):为了简化置换,所以将A和B两次置换合并,在置换群中有一个定
理:设T^k = e,(T为一置换,e为单位置换(映射函数为的置换)),那么k的最小正整数解是T的
拆分的所有循环长度的最小公倍数。所根据此定理求出循环节长度 ,同时可以知道 循环节长度*2
就是偶数时达到目标状态的答案;
2. 奇数情况(A比B刷牌次数多一):在偶数情况已经计算出循环节了,只要A*B的置换可以变成A的逆
即可,到此p[i] 和 r[i] 就都可以求出来了,进行一次CRT,CRT的答案 * 2+1 就是奇数情况的答
案。
最后答案取奇偶分类讨论中,较小的一个作为答案ans,如果ans大于1e12,输出 "huge",否则输出
ans.
时间复杂度:O(n*lgn)
空间复杂度:O(n)*/
E题目
E Efficient Exchange
Time limit: 3s
You have recently acquired a new job at the Bank for Acquiring
Peculiar Currencies. Here people can make payments, and de-
posit or withdraw money in all kinds of strange currencies. At
your first day on the job you help a customer from Nijmegia, a
small insignificant country famous for its enormous coins with
values equal to powers of 10, that is, 1,10,100,1000, etc. This
customer wants to make a rather large payment, and you are
not looking forward to the prospect of carrying all those coins
to and from the vault.
You therefore decide to think things over first. You have an
enormous supply of Nijmegian coins in reserve, as does the customer (most citizens from
Nijmegia are extremely strong). You now want to minimize the total number of coins that
are exchanged, in either direction, to make the exact payment the customer has to make.
For example, if the customer wants to pay 83 coins there are many ways to make the exchange.
Here are three possibilities:
Option 1. The customer pays 8 coins of value 10, and 3 coins of value 1. This requires
exchanging 8 + 3 = 11 coins.
Option 2. The customer pays a coin of value 100, and you return a coin of value 10, and 7
coins of value 1. This requires exchanging 1 + 1 + 7 = 9 coins.
Option 3. The customer pays a coin of value 100, and 3 coins of value 1. You return 2 coins
of value 10. This requires exchanging 1 + 3 + 2 = 6 coins.
It turns out the last way of doing it requires the least coins possible.
Input
• A single integer 0 ≤ n < 10 1000 , the amount the customer from Nijmegia has to pay.
Output
• Output the minimum number of coins that have to be exchanged to make the required
payment.
Sample Input 1 Sample Output 1
83 6
12 Problem E: Efficient Exchange
Sample Input 2 Sample Output 2
13 4
Sample Input 3 Sample Output 3
0 0
Sample Input 4 Sample Output 4
12345678987654321 42
代码(原题解代码)
#include<iostream>
#include<cstring>
using namespace std;
int dp[10005][2];
int main(){
char s[10005];
scanf("%s",s);
dp[0][1]=1;
dp[0][0]=0;
for(int i=0;i<strlen(s);i++){
dp[i+1][0]=min(dp[i][0]+s[i]-'0',dp[i][1]+10-s[i]+'0');
dp[i+1][1]=min(dp[i][0]+s[i]-'0'+1,dp[i][1]+10-s[i]+'0'-1);
}
printf("%d",dp[strlen(s)][0]);
return 0;
}
感想
居然是dp,开始以为跟之前换钱的一类题型一样,但是这次情况更多,很多次超时,因此也被罚了很多时,而且还没过,最后的样例一直过不了。
F题目
F Find my Family Time limit: 7s
CC-BY 2.0 By Ivan on Flickr
You are looking for a particular family photo with
you and your favorite relatives Alice and Bob. Each
family photo contains a line-up of n people. On the
photo you’re looking for, you remember that Alice,
who is taller than you, was somewhere on your left
from the perspective of the photographer. Also, Bob
who is taller than both you and Alice, was standing
somewhere on your right.
Since you have a large number of family photos, you want to use your computer to assist
in finding the photo. Many of the photos are quite blurry, so facial recognition has proven
ineffective. Luckily, the Batch Apex Photo Classifier, which detects each person in a photo
and outputs the sequence of their (distinct) heights in pixels, has produced excellent results.
Given this sequence of heights for k photos, determine which of these photos could potentially
be the photo you’re looking for.
Input
• The first line contains 1 ≤ k ≤ 1000, the number of photos you have to process.
• Then follow two lines for each photo.
– The first line contains a single integer 3 ≤ n ≤ 3 · 10 5 , the number of people on
this photo.
– The second line contains n distinct integers 1 ≤ h 1 ,...,h n ≤ 10 9 , the heights of
the people in the photo, from left to right.
It is guaranteed that the total number of people in all photos is at most 3 · 10 5 .
Output
• On the first line, output the number of photos k that need further investigation.
• Then print k lines each containing a single integer 1 ≤ a i ≤ n, the sorted indices of the
photos you need to look at.
Sample Input 1 Sample Output 1
1
3
2 1 3
1
1
14 Problem F: Find my Family
Sample Input 2 Sample Output 2
4
4
140 157 160 193
5
15 24 38 9 30
6
36 12 24 29 23 15
6
170 230 320 180 250 210
2
2
4
代码(原题解代码)
#include <bits/stdc++.h>
using namespace std;
const int N = 3e5+7,INF = 0x3f3f3f3f;
int k,n,Max;
int a[N],max_bh[N];
vector<int> ans;
int main(){
scanf("%d",&k);
for(int i=1;i <= k;i++){
scanf("%d",&n);
for(int j=1;j <= n;++j) scanf("%d",a+j);
for(int j=n;j > 0; --j)
if(a[j] > Max) max_bh[j] = a[j] , Max = a[j];
else max_bh[j] = Max;
set<int> st;
Max = 0;
for(int j=1;j <= n;++j){
if(!st.size() || a[j] == max_bh[j]){
st.insert(a[j]); continue;
}
auto pos = st.upper_bound(a[j]);
if(pos != st.end()){
if(*pos < max_bh[j]){
ans.push_back(i);
break;
}
}
st.insert(a[j]);
}
}
printf("%d\n",ans.size());
for(int i=0;i < ans.size(); ++i)
printf("%d\n",ans[i]);
return 0;
}
感想
/*题目意思很直白,找出存在中间的数比左边的数小,右边的数比左边的数大,如果对于暴力求法,在 n
次情况下必定超时,此时就需要两个客观意义上的指针。首先解决右边的数,那么我们把第 i 个数以后
最大的数找出,就可以解决右边数的最大值,剩下的就是左边的数,我们可以同过 set 和二分来查找出
比当前 数恰好大一点的数, 若有,再用此数 和右边的最大数相比即可。*/
自己打的时候也是套循环超时,因为再找这三个人上面一直找不到合适的方法,开始还以为是查最值,耽误了很多时间。
G题目
G Gluttonous Goop
Time limit: 3s
As a prominent researcher in the laboratorium for Breathtaking Agriculture through Petri
dish Cultivation, you keep on looking for new organisms that might be the food of the future.
Recently you have discovered a new fungus-type organism that seems to be nutritious and
very efficient in converting energy from food to body mass. You have placed a small batch
surrounded by food in a petri dish and watched it grow for a bit.
However, now that the weekend has arrived, you would rather spend some time with your
loved ones than stare at the contents of this petri dish all the time (even though it is a
fun guy). You cannot leave without taking the necessary precautions. What if the fungus
grows too large and starts eating away at the rest of the laboratory?!
You model the situation as follows: you divide the plane into 1 × 1-squares, and draw where
the fungus currently is. You know that every time step, if the fungus occupies a square, it
will expand to all eight neighbouring squares (and still occupy the initial square). You know
how many time steps you will be gone for over the weekend, and now you want to know how
many squares the fungus will occupy when you get back.
Figure G.1: Example of fungus growth: the fungus from sample 2 after 0, 1, 2 time steps. The middle
image corresponds to the correct output for sample 2.
N.B.: In the input, the fungus will be given on a finite grid, but it can (and will!) grow
beyond these boundaries. The fungus is not so easily contained.
Input
• First a line containing integers 1 ≤ r,c ≤ 20, and 0 ≤ k ≤ 10 6 , denoting the number of
rows and columns of the initial grid and the number of time steps.
• Then follow r lines of c characters, each character being either ‘.’ or ‘#’. A ‘#’ denotes
that the fungus is occupying this square. The fungus need not be connected.
Output
• Output the number of squares the fungus occupies after k time steps have passed.
16 Problem G: Gluttonous Goop
Sample Input 1 Sample Output 1
5 5 3
.....
.###.
.#.#.
.###.
.....
81
Sample Input 2 Sample Output 2
3 3 1
#..
.#.
..#
19
Sample Input 3 Sample Output 3
4 6 3
..##..
.#..#.
.#..#.
..##..
96
Sample Input 4 Sample Output 4
1 1 1000000
#
4000004000001
代码(原题解代码)
#include <cstdio>
#include <iostream>
typedef long long ll;
const int N = 66;
bool form[N][N];
ll cnt, res = 1;
int main() {
int r, c, k;
scanf("%d%d%d", &r, &c, &k);
char s[c];
int num = k>20?20:k;// 模拟的步数
for (int i = 0; i < r; ++i) {
scanf("%s", s);
for (int j = 0; j < c; ++j)
if (s[j] == '#') {
form[i+20][j+20] = true;
for (int x = -num; x <= num; ++x)
for (int y = -num; y <= num; ++y)
form[i+20+x][j+20+y] = true;
}
}
int minr=N, minc=N, maxr=0, maxc=0;
for (int i=20-num, t=r+20+num; i < t; ++i)
for (int j=20-num, tt=c+20+num; j < tt; ++j) {
if (form[i][j] == true) {// 计数并找边框的长、宽
cnt ++;
minr = std::min(minr, i);
minc = std::min(minc, j);
maxr = std::max(maxr, i);
maxc = std::max(maxc, j);
}
}
if (cnt && k>20) {// (2)
ll h = maxr - minr + 1;
ll w = maxc - minc + 1;
ll miss = h*w - cnt;
res *= h+(k-num<<1);
res *= w+(k-num<<1);
printf("%lld", res - miss);
} else
printf("%lld", cnt);
return 0;
}
感想
/*每过一 time step,真菌就会向其相邻的八个格子蔓延。求经过k个time steps后,被真菌所占的格子的
总数。
1 ≤ r、c ≤ 20,0 ≤ k ≤ 1e6。最大结果:(2 * 10^6 + 20)^2 ≈ 4 * 10^12,在 long long范围内
(1)K <= 20时,模拟真菌蔓延
(2)k > 20时,填补法,计算边框的长、宽,用大矩形的面积减去边角的面积。边角的面积就是模拟
20次真菌蔓延后,使用填补法添加的面积。*/
刚开始还以为是像上次一个环形虫的题型,但是理解错了,打算用八个方位计算的算法但是自己越想越偏了。
H题目
H Historic Exhibition
Time limit: 1s
The Benelux Artistic Pottery Consortium is preparing for an exhibit of its most prized urns
and vases at a gallery in Nijmegen. Due to the sheer number of vases to be put on display the
gallery has trouble finding a pedestal of the right size for every single vase. They have pedestals
available that can either be placed normally or upside down and can be characterised by the
diameter of their top and bottom surface. Moreover, the diameter of the top and bottom
varies by at most one unit length.
For artistic reasons, it is important that the diameter of the base of a vase matches the
diameter of the surface of the pedestal it is placed on. You have been asked to find a way to
place all the vases on available pedestals. In order to make this work, you might need to turn
some of the pedestals upside down. For example, Figure H.1 shows a possible assignment of
pedestals to vases for sample input 1. Assist the gallery by writing a program to compute
such an assignment.
2 2 2
1 2 3
1 2 3
Figure H.1: Solution for sample input 1.
Input
• The first line contains two integers 0 ≤ p,v ≤ 10 4 the number of pedestals and the
number of vases.
• Then follow p lines, the i-th of which contains two integers 1 ≤ a i ,b i ≤ 10 4 denoting
the diameters of the different sides of pedestal i. It is given that |a i − b i | ≤ 1.
• Then follows a single line containing v integers 1 ≤ c 1 ,...,c v ≤ 10 4 , where c i denotes
the diameter of vase i.
Output
• Output v distinct integers 1 ≤ x 1 ,...,x v ≤ p such that vase i can stand on pedestal x i ,
or print impossible if no assignment of vases to pedestals exists.
If there are multiple possible solutions, you may output any one of them.
18 Problem H: Historic Exhibition
Sample Input 1 Sample Output 1
4 3
1 2
4 5
2 3
2 2
1 2 3
1
4
3
Sample Input 2 Sample Output 2
2 2
1 1
2 3
1 1
impossible
Sample Input 3 Sample Output 3
2 3
9 8
4 5
4 9 5
impossible
代码(原题解代码)
#include<iostream>
#include<algorithm>
#include<unordered_map>
#include<stack>
const int MAXN = 1e4+10;
int ans[MAXN];
struct node{
int x, id;
friend bool operator < (node a, node b){
return a.x==b.x ? a.id<b.id : a.x<b.x;
}
}va[MAXN];
std::unordered_map<int,std::stack<int> > mp1, mp2;
int main(){
int p, v;
scanf("%d%d", &p, &v);
for(int i = 1, a, b; i <= p; i++){
scanf("%d%d", &a, &b);
if(a == b) mp1[a].push(i);
else mp2[std::min(a, b)].push(i);
}
for(int i = 1, x; i <= v; i++){
scanf("%d", &x);
va[i].id = i, va[i].x = x;
}
std::sort(va+1, va+1+v);
for(int i = 1; i <= v; i++){
if(!mp1[va[i].x].empty()){
ans[va[i].id] = mp1[va[i].x].top();
mp1[va[i].x].pop();
}
else if(!mp2[va[i].x-1].empty()){
ans[va[i].id] = mp2[va[i].x-1].top();
mp2[va[i].x-1].pop();
}
else if(!mp2[va[i].x].empty()){
ans[va[i].id] = mp2[va[i].x].top();
mp2[va[i].x].pop();
}
else{
printf("impossible\n");
return 0;
}
}
for(int i = 1; i <= v; i++)
printf("%d\n",ans[i]);
return 0;
}
感想
自己判断时满足条件,样例也过了。但是还是出错,是答案错误,但是特殊情况一直没能找到,自己代码跟题解比缺了很多自己没想到的,是自己想的太少了,要加强练习。
I题目
I Inquiry II Time limit: 5s
For an undirected, simple graph G = (V,E) we call a subset V
0
⊆ V an independent set if no
two elements of V
0
are connected by an edge. An independent set of G is called a maximum
independent set if there is no independent set in G with strictly more vertices. Given a specific
kind of connected graph G, find the size of a maximum independent set of G.
Input
• The input starts with one line, containing integers n (1 ≤ n ≤ 100), the number of
vertices in the graph, and m (n − 1 ≤ m ≤ n + 15), the number of edges in the graph.
• Then follow m lines, each containing integers a,b (1 ≤ a,b ≤ n) indicating that there is
an edge between vertices a and b.
The graph given by this input is guaranteed to be both simple and connected: there is at
most one edge between each pair of vertices, there are no loops, and there is a path between
each pair of vertices.
Output
• Output the number of vertices in a maximum independent set of the input graph.
Sample Input 1 Sample Output 1
2 1
1 2
1
Sample Input 2 Sample Output 2
4 5
1 2
2 3
3 4
4 1
1 3
2
代码(原题解代码)
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
using namespace std;
const int N = 240;
typedef pair<int, int> PII;
int n, m, cnt, idx;
int head[N], ne[N], to[N];
int fa[N], spe[N][2], dp[N][2];
bool vis[N];
void add(int u, int v){
to[++idx] = v, ne[idx] = head[u], head[u] = idx;
}
int Get(int x){
if(x != fa[x]) fa[x] = Get(fa[x]);
return fa[x];
}
void Merge(int x, int y){
fa[Get(x)] = Get(y);
}
bool is_Same(int x, int y){
if(Get(x) == Get(y)) return true;
return false;
}
void tp(int u,int fa){
if(!vis[u]) dp[u][1] = 1;
for(int i = head[u]; ~i; i = ne[i]){
int v = to[i];
if(v == fa) continue;
tp(v, u);
dp[u][0] += max(dp[v][1], dp[v][0]);
dp[u][1] += dp[v][0];
}
}
int main(){
memset(head, -1, sizeof head);
scanf("%d%d", &n, &m);
int k = m-n+1;
for(int i = 1; i <= n; i++) fa[i] = i;
while(m--){
int u, v;
scanf("%d%d", &u, &v);
if(is_Same(u, v)){
spe[cnt][0] = u, spe[cnt][1] = v;
cnt++;
}
else{
add(u, v);
add(v, u);
Merge(u, v);
}
}
int ans = 0;
for(int t = 0; t < (1<<k); t++){
memset(vis, false, sizeof vis);
memset(dp, 0, sizeof dp);
for(int i = 0; i < k; i++) vis[spe[i][(t>>i)&1]] = true;
tp(1, -1);
ans = max(ans, max(dp[1][0], dp[1][1]));
}
printf("%d\n", ans);
return 0;
}
感想
/*对于一般图求最大独立集,都是利用 算法 建立补图计算最大团。但是本题n的最大
值达到100,对于这样一个指数级别的算法,妥妥地 TLE。我们再来观察一下数据,m的范围为
, 。此时,我们可以发现边的数量非常少,而可以构成环的边只有 条。对于
这m-(n-1)条边的每一条边而言,至少有一个端点是不在最大独立集中。所以,我们可以利用并查集找
到这 条边,利用二进制思想暴力枚举 条边每个端点的是否存在最大独立集中,这样我们可以将环移
除,将问题退化成树的情况,利用树形DP求出每种情况的最大独立集,取最大值。*/
J题目
J Jazz it Up! Time limit: 1s
Music engraving by LilyPond 2.18.2—www.lilypond.org
Along with some friends you formed the Band
of Atonal Percussionists and Cellists. You have
been playing for some years together, but you feel
unsatisfied with the current level of play. Doing
research into some interesting new styles, you are gripped by the intricate details of the world
of jazz.
While of course you cannot apply all the new things you have learned immediately, you want
to start with improvising some nice new rhythmic figures in the music your band plays. You
will play a rhythm where every bar has n beats in it, but then you split up every beat into
m notes. In total, you will have nm notes per bar.
Everyone in the band knows that there is no room for squares in jazz. So the number of notes
in a bar should be squarefree. That is, there is no number k > 1 such that k 2 divides the
number of notes in a bar.
The percussionist has already suggested a number of beats per bar n; now it is up to you to
find a number of notes per beat that does not leave any room for squares.
In the second sample we have n = 30 and m = 7. This works because 2 ≤ m < n and
m × n = 210 has no divisor k 2 for any k > 1.
Input
• The input is a single squarefree integer 3 ≤ n ≤ 10 5 .
Output
• Output an integer 2 ≤ m < n such that m × n is still squarefree.
If there are multiple possible solutions, you may output any one of them.
Sample Input 1 Sample Output 1
3 2
Sample Input 2 Sample Output 2
30 7
Sample Input 3 Sample Output 3
13 10
代码(原题解代码)
#include<cstdio>
#include<cstring>
#define ll long long
const ll N=1e5+7;
ll prime[N],ans,n,prime_tot = 0;
bool prime_tag[N];
void get_prime(){
for(int i = 2; i < N; i++){
if(!prime_tag[i]){
prime[prime_tot++] = i;
}
for(int j = 0; j < prime_tot && i * prime[j] < N; j++){
prime_tag[i * prime[j]] = true;
if(i % prime[j] == 0) break;
}
}
prime_tag[1] = true;
}
int main(){
get_prime();
scanf("%lld",&n);
for(ll i=0;i<prime_tot;i++){
if(n%prime[i]){
ans=prime[i];
break;
}
}
printf("%lld\n",ans);
}
感想
依旧是过样例但是答案错误,而且自己的耗时明显更大。
/*此题题目要求, 的因子中不能含有平方形式,因为题目中已经说明 是一个无平方因子的数,
那么只要 是无平方因子的数,并且 和 没有共同的因子即可。
根据算术基本定理, 可以分解成若干个质数的积,所以 就直接可以是非 的因子的一个质数。*/
K题目
K Keep Him Inside
Time limit: 1s
As a result of a long-standing war between the Sorcerers and the Orcs, you have been assigned
as officer of one of the prison blocks. Recently the leader of the Orcs has been captured and
placed inside a special cell. It works as follows: the cell is a convex polygon with at every
vertex a guard tower in which a Sorcerer is placed.
Thanks to the recent agreement between the Sorcerers and Orcs, called the Beneficial Activ-
ities for Prisoners in Cells, the leader of the Orcs should be able to move around freely in his
cell. You do not want your prisoner to escape, so you order the sorcerers to work together on
a containment spell. If done right, this creates a magical aura around the prisoner that will
prevent him from escaping.
In order for the containment spell to work, all Sorcerers need to channel a certain fraction of
their maximum power into the spell such that two things hold:
• The spell needs to be perfectly balanced: the sum of the fractions of power over all
Sorcerers must equal 1.
• The centre of the spell should coincide with the prisoner. This means that the average
of the positions of Sorcerers, weighted by the fraction of power they are channeling,
should be the location of the prisoner.
Given the layout of the cell and the location of the prisoner, assign a fraction of power each
Sorcerer should spend so that the containment spell works.
S 1 : 1/3 S 2 : 1/3
S 3 : 1/3
P
Figure K.1: The prison of sample 1. S 1 , S 2 , and S 3 are the Sorcerers, while P is the prisoner. Note
that
1
3 S 1
+
1
3 S 2
+
1
3 S 3
=
1
3 (0,0) +
1
3 (3,0) +
1
3 (0,3) = (1,1) = P.
Input
• The first line contains 3 ≤ n ≤ 10, the number of Sorcerers in guard towers and two
integers −10 4 ≤ x,y ≤ 10 4 , the coordinates of the prisoner.
• Then follow n lines, each of which contains two integers −10 4 ≤ x,y ≤ 10 4 , the coordi-
nates of a Sorcerer.
24 Problem K: Keep Him Inside
It is guaranteed that the locations are given in counter clockwise order and form a strictly
convex polygon, i.e. no three points lie on a line. The prisoner is located strictly inside the
polygon.
Output
• Output n lines where the ith line contains a floating point number between 0 and 1
inclusive: the fraction of power that the ith Sorcerer should use for the containment
spell to work.
If there are multiple possible solutions, you may output any one of them.
Your answer will be correct if the sum of fractions differs at most 10 −4 from 1 and the weighted
centre of your spell is within distance 10 −4 of the prisoner. Note that it may not be sufficient
to print your answer itself with 10 −4 precision.
Sample Input 1 Sample Output 1
3 1 1
0 0
3 0
0 3
0.333333333333
0.333333333333
0.333333333333
Sample Input 2 Sample Output 2
4 2 1
0 0
4 0
4 4
0 4
0.5
0.25
0.25
0
Sample Input 3 Sample Output 3
5 4 3
0 2
0 -1
5 -2
5 4
2 5
0.2
0
0.1
0.7
0
代码(原题解代码)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e4+5;
ll xa,xb,xc,ya,yb,yc,px,py;
double a,b,c,ans[maxn];
int n;
struct node //用来记录巫师所在点的坐标
{
ll x,y;
}no[20];
int main()
{
cin >> n >> px >> py; //px,py表示P点的坐标
for(int i = 0 ; i < n ; i++)
cin >> no[i].x >> no[i].y;
xc = no[0].x,yc = no[0].y;
xb = no[1].x,yb = no[1].y;
px -= xc,py -= yc;
xb -= xc,yb -= yc;
for(int i = 2 ; i < n ; i++)
{
xa = xb,ya = yb;
xb = no[i].x,yb = no[i].y;
xb -= xc,yb -= yc;
double f = xb*ya - xa*yb;//表示上述公式中a,b前面的系数
a = (xb*py - px*yb)/f;
b = (px*ya - py*xa)/f;
c = 1 - a - b;
if(a >= 0 && b >= 0 && c >= 0)//要保证计算出的权值全为正,并记录在ans中
{
ans[0] = c; //c对应的是x3也就是这里的xc,对应点的下标为0
ans[i-1] = a; //a对应的是x1也就是这里的xa,对应点的下标为i-1
ans[i] = b; //b对应的是x2也就是这里的xb,对应点的下标为i
}
}
for(int i = 0 ; i < n ; i++)
cout << setprecision(12) << ans[i] << endl;
return 0;
}
感想
/*是一道构造几何的问题,问题可以转变为给巫师所在的每个点一个权重,使得这些点的加权和等于
P,也就是要满足这个公式,v表示每个点的权值,s表示每个点的坐标*/
当时没来得及做,后来读题了解了一些,但是还是没能自己做出来
L题目
L Lucky Draw Time limit: 2s
You and your friends at the Betting against All Probability Club
are visiting a casino where the following game is played.
Each of the n players starts with k lives and puts in a fixed amount
of money. In each round of the game, each player flips a biased
coin and loses a life if she gets tails. The game ends when only
one player remains, in which case this person wins, or ends in a
draw if all remaining players lose their last life in the same round.
If there is a winner, she wins n times her original bet. In case of
a draw, no one wins anything.
Being a BAPC member you quickly realize the casino has an edge
here: whenever the game ends in a draw all of the contestants lose
the money they bet. You are now wondering what exactly is the
probability that this game ends in a draw, so you can figure out
how much the casino profits on average.
Input
• One line containing two integers, 2 ≤ n ≤ 50, the number of players, 1 ≤ k ≤ 50,
the number of lives each player has, and a floating point number 0.1 ≤ p ≤ 0.9, the
probability the coin lands heads.
Output
• Output a single floating point number: the probability of the game ending in a draw.
Your answer should have an absolute error of at most 10 −6 .
Sample Input 1 Sample Output 1
2 2 0.5 0.185185185
Sample Input 2 Sample Output 2
2 2 0.8 0.056241426
Sample Input 3 Sample Output 3
5 3 0.85 0.045463964
代码(原题解代码)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN=1e3;
long double c[MAXN+10][MAXN+10];
void init(){
c[0][0]=1;
for(int i=1;i<=MAXN;i++){
c[i][0]=c[i][i]=1;
for(int j=1;j<i;j++){
c[i][j]=c[i-1][j]+c[i-1][j-1];
}
}
}
int main(){
init();
int n,k;
double p;
scanf("%d%d",&n,&k);
scanf("%lf",&p);
double cur=0;
double tot=0;
double ans=1;
for(int i=1;i<=MAXN;i++){
if(i>=k){
double P=c[i-1][k-1]*pow(p,i-k)*pow(1-p,k);
tot=tot+P*pow(cur,n-1);
cur=cur+P;
}
}
ans=1-n*tot;
printf("%.6lf\n",ans);
return 0;
}
感想
/游戏最后只有两个结局,平局或者有人胜出,所以可把求平局概率的问题转化为求
有人胜出概率的问题。每个人life数相同,所以求出其中某1个人胜出的概率乘n就是有人胜出的概率。
由于存在多人一直抽不到反面的情况,所以我们取一个比较大的回合数(1000足矣),保证误差小于题
目给出的范围。某1人胜出的条件为在当前回合只剩他一个,所以求出他在第i回合死并且其他人在第i回
合之前死的概率即可,每个人在每个回合死亡的概率都相同,所以实际上其他人在第i回合之前死的概率
等于我们所求这某1个人**/
补题报告
题目
Given a time in Beijing time (UTC +8), Chiaki would like to know the time in another time zone ss.
InputThere are multiple test cases. The first line of input contains an integer TT (1≤T≤1061≤T≤106), indicating the number of test cases. For each test case:
The first line contains two integers aa, bb (0≤a≤23,0≤b≤590≤a≤23,0≤b≤59) and a string ss in the format of "UTC+X'', "UTC-X'', "UTC+X.Y'', or "UTC-X.Y'' (0≤X,X.Y≤14,0≤Y≤90≤X,X.Y≤14,0≤Y≤9).OutputFor each test, output the time in the format of hh:mmhh:mm (24-hour clock).
Sample Input
3 11 11 UTC+8 11 12 UTC+9 11 23 UTC+0
Sample Output
11:11 12:12 03:23
代码
#include<cstdio>//参考了题解
#include<cstring>
#include<cmath>
#include<iostream>
using namespace std;
int main()
{
int hour,m,N;
double d;/*注意*/
char ch;
int a,b,n;
while(scanf("%d",&N)!=EOF)
{
while(N--)
{
scanf("%d %d UTC%c%lf",&hour,&m,&ch,&d);
a=hour*60+m;
n=(int)(d*10);
if(ch=='+')
{
b=a+n*6-8*60;
}
else if(ch=='-')
{
b=a-n*6-8*60;
}
b=b%(24*60);
if(b<0) b+=24*60;
hour=b/60;
m=b%60;
printf("%02d:%02d\n",hour,m);
}
}
return 0;
}
感想
前面超限了两次,后来修改了几次发现是循环条件错误。
题目
InputThe first line of the input contains an integer T(1<=T<=20) which means the number of test cases. Then T lines follow, each line starts with a number N(1<=N<=100000), then N integers followed(all the integers are between -1000 and 1000).
OutputFor each test case, you should output two lines. The first line is "Case #:", # means the number of the test case. The second line contains three integers, the Max Sum in the sequence, the start position of the sub-sequence, the end position of the sub-sequence. If there are more than one result, output the first one. Output a blank line between two cases.
Sample Input
2 5 6 -1 5 4 -7 7 0 6 -1 1 -6 7 -5
Sample Output
Case 1: 14 1 4 Case 2: 7 1 6
代码
#include<cstdio>/*有参考题解*/
#include<cstring>
#include<cmath>
#include<iostream>
#include<bits/stdc++.h>
#include<algorithm>
using namespace std;
int a[200000];
int b[200000];
int s,e,t1,t2;
int main()
{
int n;
scanf("%d",&n);
int i=1;
while(i<=n)
{
printf("Case %d:\n",i);/*输入注意!!!*/
int m;
scanf("%d",&m);
int j;
for(j=0;j<m;j++)
scanf("%d",&a[j]);
int M=-999;
s=0;
t2=0;
b[0]=a[0];
for(int j=0;j<m;j++)
{
/*自己前几遍打的时候也是写了一个数组元素与输入相同*/
if(b[j-1]>=0)
{
/*但是在这里思路就不同了*/
b[j]=b[j-1]+a[j];
t1=j;
}
else
{
/*这里求和并更新,自己则是先排了序取开始和末尾,就是漏掉了相同元素的情况*/
b[j]=a[j];
t1=j;
s=j;
}
/*判断坐标*/
if(M<b[j])
{
M=b[j];
e=s;
t2=t1;
}
}
printf("%d %d %d\n",M,e+1,t2+1);
if(i!=n)
printf("\n");
i++;
}
return 0;
}
感想
跟参考题解思路大致一样,但是在数组存入时就不同了,后来自己的一直过不了,是在数组那里出的错,于是又按题解方法打了一遍。
题目
Thanks to LCY, I have this chance to share my ideas and works with you. Good luck and have fun!
================
We have a graph with size = N like that in Figure 1. Then we are going to find a downward path from the top node to one bottom node.
First, we select the top node as the beginning. Then at any node, we can go horizontally or downward along the blue edge and reach the next node. The finding will be end when we reach one of the bottom nodes. After that we can get a downward path from the top node to one bottom node. Note that we can not pass a blue edge that we have passed ago during each finding.
Your task is to calculate there exists how many downward paths.
Input There is an integer T (1 <= T <= 1000) in the first line, which indicates there are T test cases in total.
For each test case, there is only one integer N (1 <= N <= 10^18) indicates the size of the graph.Output For each test case, you should output the correct answer of the above task in one line.
Because the answer may be very large, you should just output the remainder of it divided by 1000003.Sample Input
2 1 2
Sample Output
2 8
代码
#include <iostream>
#include<cstdio>
#include <cstring>
#define M 1000003
using namespace std;
long long num[M+5];
int i;/*放外面*/
int main()
{
int N;
long long m;
num[0]=0;
num[1]=2;
for(i=2;i<M;i++)
num[i]=num[i-1]*2*i%M;
scanf("%d",&N);
while(N--)
{
scanf("%lld",&m);
if(m>=M)
{printf("0\n");}
else
{printf("%lld\n",num[m]);}
}
return 0;
}
感想
是个找规律的题型,明白规律就好做了。期间还超了一次时。
/*a1=2=1+1;
a2=8=2+2*2+2;
a3=48=8+8*2+8*2+8;*/
题目
InputMulti test cases, every case occupies two lines, the first line contain n, then second line contain n numbers a 1, a 2, ……a n separated by exact one space. Process to the end of file.
[Technical Specification]
2 <= n <= 100
-1000000000 <= a
i <= 1000000000OutputFor each case, output the final sum.Sample Input
4 1 2 3 4 2 5 5
Sample Output
25 10
代码
#include<cstdio>
#include<cstring>/*题解有参考算法*/
#include<cmath>
#include <algorithm>
#include<iostream>
#define N 105
using namespace std;
int main ()
{
int n;
long long a[N],b[10005];
while(~scanf("%d",&n))
{
if(n<2){break;}
long long i,j,k;
for(i=0;i<n;i++)
{
scanf("%I64d",&a[i]);/*1000000000会溢出*/
}
long long c=0;
for(i=0;i<n;i++)
{
for(j=i+1;j<n;j++)
{
b[c]=a[i]+a[j];
c++;
}
}
sort(b,b+c);
for(i=0;i<c+1;i++)
{
if(i<=c-2)
{
if(b[i]==b[i+1])
{
b[i]=0;
}
}
}
long long sum=0;
for(i=0;i<c;i++)
{
sum+=b[i];
}
printf("%I64d\n",sum);
}
return 0 ;
}
感想
参考了题解,但自己打的时候没有注意范围,溢出了,后来改掉了,以后更要注意细节了
题目
Input每组测试数据有两行,第一行有两个数n,m(0<n,m<1000000),第二行包含n个各不相同,且都处于区间[-500000,500000]的整数。
Output对每组测试数据按从大到小的顺序输出前m大的数。
Sample Input
5 3 3 -35 92 213 -644
Sample Output
213 92 3
代码
#include<cstdio>
#include<cstring>/*题解有参考算法*/
#include<cmath>
#include <algorithm>
#include<iostream>
#define N 2000000
using namespace std;
int a[N];
int main ()
{
int n,i,j,k;
while(scanf("%d %d",&n,&k)!=EOF)
{
int m;
memset(a,0,sizeof(a));/*使数组清零*/
while(n--)
{
scanf("%d",&m);
a[m+500000]++;/*后部存储*/
}
for(i=1000000;k!=0;i--)/*倒序输入*/
{
if(a[i]>0)
{
printf("%d",i-500000);
if(k>1)
{
cout<<" ";
}
k--;
}
}
cout<<endl;
}
return 0 ;
}
感想
/*自己打了一次sort排序但是超时了,以为是int a[N]没放到外部,但还是没有出结果于是参考了题解*/
题目
“是的。”
“那你干什么呢?”
“看世界杯呀,笨蛋!”
“@#$%^&*%...”
确实如此,世界杯来了,球迷的节日也来了,估计很多ACMer也会抛开电脑,奔向电视了。
作为球迷,一定想看尽量多的完整的比赛,当然,作为新时代的好青年,你一定还会看一些其它的节目,比如新闻联播(永远不要忘记关心国家大事)、非常6+7、超级女生,以及王小丫的《开心辞典》等等,假设你已经知道了所有你喜欢看的电视节目的转播时间表,你会合理安排吗?(目标是能看尽量多的完整节目)
Input输入数据包含多个测试实例,每个测试实例的第一行只有一个整数n(n<=100),表示你喜欢看的节目的总数,然后是n行数据,每行包括两个数据Ti_s,Ti_e (1<=i<=n),分别表示第i个节目的开始和结束时间,为了简化问题,每个时间都用一个正整数表示。n=0表示输入结束,不做处理。
Output对于每个测试实例,输出能完整看到的电视节目的个数,每个测试实例的输出占一行。Sample Input
12 1 3 3 4 0 7 3 8 15 19 15 20 10 15 8 18 6 12 5 10 4 14 2 9 0
Sample Output
5
代码
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int main(){
int n,i,j,k,a[1000],b[1000],c;
while(scanf("%d",&n)!=EOF)
{
if(n==0){break;}
for(i=0;i<n;i++)
{
scanf("%d %d",&a[i],&b[i]);
}
for(i = 0;i<n-1;i++)
{
for(j=i+1;j<n;j++)
{
if(b[i]>b[j])/*当初自己是在这里用了排序的函数。*/
{
k=a[i];
a[i]=a[j];
a[j]=k;
k=b[i];
b[i]=b[j];
b[j]=k;
}
}
}
k = b[0];
c = 1;
for(i=1;i<n;i++)
{
if(k<=a[i])
{
c++;
k=b[i];
}
}
printf("%d\n",c);
}
}
感想
/*自己用sort函数排了序,从从小到大排的开始时间,然后在一个容器存
了原数组排序了结束时间最后查找时一直出错,于是参考了题解算法。*/
题目
一天,当他正在苦思冥想解困良策的时候,突然想到了自己的传家宝,那是公司成立的时候,父亲作为贺礼送来的一个锦囊,徐父当时交代,不到万不得已的时候,不要打开它。“现在不正是最需要的时候吗?”,一边想,XHD一边找到了这个精心保管的锦囊,打开一看,里面只有一句话“杭城北麓千人洞有宝”。
二话不说,XHD拿起一个大口袋就出发了,这个千人洞他是知道的,小的时候,爸爸曾经带他来过这个隐蔽的路口,并告诉他,这是千人洞。他现在才明白爸爸当初这句话的含义。
尽管有点印象,XHD还是花了很大的精力才找到这个异常隐蔽的洞口,走进一看,几乎惊呆了,真的是眼花缭乱!不过尽管宝贝的种类不少,但是每种宝贝的量并不多,当然,每种宝贝单位体积的价格也不一样,为了挽救HDU,现在请你帮忙尽快计算出来XHD最多能带回多少价值的宝贝?(假设宝贝可以分割,分割后的价值和对应的体积成正比)
Input输入包含多个测试实例,每个实例的第一行是两个整数v和n(v,n<100),分别表示口袋的容量和宝贝的种类,接着的n行每行包含2个整数pi和mi(0<pi,mi<10),分别表示某种宝贝的单价和对应的体积,v为0的时候结束输入。
Output对于每个测试实例,请输出XHD最多能取回多少价值的宝贝,每个实例的输出占一行。
Sample Input
2 2 3 1 2 3 0
Sample Output
5
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
using namespace std;
int a[10000],b[10000];
int main()
{
int N,n,i,M;
while(1)
{
scanf("%d",&N);
if(N==0){break;}
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%d %d",&a[i],&b[i]);
}
int t=0;
while(N>0)
{
M=1;
for(i=0;i<n;i++)
{
if(a[i]>a[M])
{
M=i;
}
}
if(N>b[M])/*算法有参考*/
{
N=N-b[M];
t=t+b[M]*a[M];
a[M]=0;
}
else
{
t=t+N*a[M];
break;
}
}
printf("%d\n", t);
}
}
感想
排序查找单位体积最贵的即可
题目
When the typhoon came, everything is terrible. It kept blowing and raining for a long time. And what made the situation worse was that all of Kitty's walls were made of wood.
One day, Kitty found that there was a crack in the wall. The shape of the crack is
a rectangle with the size of 1×L (in inch). Luckly Kitty got N blocks and a saw(锯子) from her neighbors.
The shape of the blocks were rectangle too, and the width of all blocks were 1 inch. So, with the help of saw, Kitty could cut down some of the blocks(of course she could use it directly without cutting) and put them in the crack, and the wall may be repaired perfectly, without any gap.
Now, Kitty knew the size of each blocks, and wanted to use as fewer as possible of the blocks to repair the wall, could you help her ?
InputThe problem contains many test cases, please process to the end of file( EOF ).
Each test case contains two lines.
In the first line, there are two integers L(0<L<1000000000) and N(0<=N<600) which
mentioned above.
In the second line, there are N positive integers. The i
th integer Ai(0<Ai<1000000000 ) means that the i
th block has the size of 1×Ai (in inch).
OutputFor each test case , print an integer which represents the minimal number of blocks are needed.
If Kitty could not repair the wall, just print "impossible" instead.
Sample Input
5 3 3 2 1 5 2 2 1
Sample Output
2 impossible
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
int bijiao(int x,int y){
if(x>y){return 1;}
else{return 0;}
}
int main()
{
int L,N,a[1000];
int i,j;
while(scanf("%d %d",&L,&N)!=EOF)
{
if(L==0){break;}
for(i=0;i<N;i++)
{
scanf("%d",&a[i]);
}
int m=0,n=0;
sort(a,a+N,bijiao);/*尽可能少*/
for(i=0;i<N;i++){
if(m<L)
{/*如果小于,的可以补,尽可能少*/
m+=a[i];
n++;
}
}
if(m<L){
printf("impossible\n");
}
else{
printf("%d\n",n);
}
}
return 0;
}
感想
当时卡在了尽可能少上面,后来其实直接找最大的一块就可以了。
题目
Consider the following algorithm:
1. input n
2. print n
3. if n = 1 then STOP
4. if n is odd then n <- 3n + 1
5. else n <- n / 2
6. GOTO 2
Given the input 22, the following sequence of numbers will be printed 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1
It is conjectured that the algorithm above will terminate (when a 1 is printed) for any integral input value. Despite the simplicity of the algorithm, it is unknown whether this conjecture is true. It has been verified, however, for all integers n such that 0 < n < 1,000,000 (and, in fact, for many more numbers than this.)
Given an input n, it is possible to determine the number of numbers printed (including the 1). For a given n this is called the cycle-length of n. In the example above, the cycle length of 22 is 16.
For any two numbers i and j you are to determine the maximum cycle length over all numbers between i and j.
InputThe input will consist of a series of pairs of integers i and j, one pair of integers per line. All integers will be less than 1,000,000 and greater than 0.
You should process all pairs of integers and for each pair determine the maximum cycle length over all integers between and including i and j.
You can assume that no opperation overflows a 32-bit integer.
OutputFor each pair of input integers i and j you should output i, j, and the maximum cycle length for integers between and including i and j. These three numbers should be separated by at least one space with all three numbers on one line and with one line of output for each line of input. The integers i and j must appear in the output in the same order in which they appeared in the input and should be followed by the maximum cycle length (on the same line).
Sample Input
1 10 100 200 201 210 900 1000
Sample Output
1 10 20 100 200 125 201 210 89 900 1000 174
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>/*有参考*/
using namespace std;
int main()
{
long long a,b,M,N;
while(scanf("%lld%lld",&a,&b)!=EOF)
{
long long i,k,t,max=0;
if(a>b) {
M=a;
N=b;
}
else {
M=b;
N=a;
}
for(i=N;i<=M;i++)
{
k=1;
t=i;
while(t>1)
{
if(t%2!=0)
{t=3*t+1;}
else
{t/=2;}
k++;
}
if(max<=k)
max=k;
}
printf("%lld %lld %lld\n",a,b,max);/*格式格式格式*/
}
return 0;
}
感想
wa到自闭,样例没有体现特殊情况,直接就wa了很多次,后来发现是自己没注意范围。
题目
Input测试输入包含若干测试用例,每个测试用例包含2行,第1行为一个长度不超过5的字符串,第2行为一个长度不超过80的字符串。注意这里的字符串包含空格,即空格也可能是要求被统计的字符之一。当读到'#'时输入结束,相应的结果不要输出。Output对每个测试用例,统计第1行中字符串的每个字符在第2行字符串中出现的次数,按如下格式输出:
c0 n0
c1 n1
c2 n2
...
其中ci是第1行中第i个字符,ni是ci出现的次数。
Sample Input
I THIS IS A TEST i ng this is a long test string #
Sample Output
I 2 i 3 5 n 2 g 2 注:第2个测试用例中,空格也是被统计的字符之一。
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
int main()
{
char a[100],b[100];
int i,j,k,a1,b1,c[6]={0};
while(gets(a))
{
if(a[0]=='#'){break;}
//scanf("%s",b);
gets(b);/*空格也是被统计的字符之一。 */
a1=strlen(a);/*记录了最后一页*/
b1=strlen(b);
for(i=0;i<a1;i++)
{
c[i]=0;
for(j=0;j<b1;j++)
{
if(a[i]==b[j])
c[i]++;
}
}
for(i=0;i<a1;i++)
printf("%c %d\n",a[i],c[i]);
}
return 0;
}
感想
自己做的时候忘了空格,后来在调试时发现了改了过来。
浙公网安备 33010602011771号