听说莫干山一日游?比赛当天体验还是略差的,没想到hdu这么大的平台能出问题= =计蒜客可能笑出了声。不过估计还是凉了,就算体验极好自己太菜还是不行啊QAQ,听说省赛四省赛能补名额,弱校也有名额,希望能续上参加一波现场赛。
1001 Buy and Resell
题解
当时做出来的好像不多,感觉并没有那么难(然而还是不会)。这个题当时还是挺亏的= =,大概思路是一样,但是没有考虑优先队列,最后还是gg了。不过现在的写法确实有些蛋疼,感觉非常的绕。
题目大概有n个城市,每次在一个城市可以购买一个物品花费ai或者卖出一个物品也是ai,求最后最大利润是多少,同时要求有最少的交易次数。整体是利用贪心,用优先队列维护购买列表,可以碰见价格低的就买,碰见高的就卖,然后可以构造出这样的情况:有序列1 2 5。首先在1买在2卖,这样赚了1块钱,变量ans记录净赚,值为1。到3的时候发现在3卖可以赚4块钱,而此时已经买一次了,但我们可以假设在2买了一次,那么就是2买3卖,净赚3元,此时对ans累加,ans是4元。这样,虽然在中间违反了规定,但是最终的结果是正确的,同时满足了贪心的算法。那么我们就可以这样来写代码,每次到中间的时候我们就记录,如果发现曾经买的不是最优,就减去一次交易次数。
最后的代码实际上对于中间变量是存进去了2次,拿例子代入代码就可理解。
代码
#include<iostream>
#include<vector>
#include<list>
#include<string>
#include<cmath>
#include<algorithm>
#include<map>
#include<set>
#include<utility>
#include<queue>
#include<sstream>
#include<iterator>
#include<math.h>
#include<malloc.h>
#include<string.h>
#include<stack>
#include<functional>
#define TIME std::ios::sync_with_stdio(false)
#define LL long long
#define MOD 1000000007
#define MAX 1000001000
#define INF 0x3f3f3f3f
using namespace std;
int T,N;
int main() {
TIME;
scanf("%d",&T);
while(T--){
scanf("%d",&N);
priority_queue<int,vector<int>,greater<int>> q;
map<int,int> step;
LL ans = 0;
LL times = 0;
int number;
for(int i = 0;i < N;i++){
scanf("%d",&number);
q.push(number);
int less_n = q.top();
if(less_n < number){
ans += (number - less_n);
times++;
q.pop();
q.push(number);
if(step[less_n] > 0){
step[less_n]--;
times--;
}
step[number]++;
}
}
printf("%lld %lld\n",ans,times*2);
}
system("pause");
return 0;
}
1004 Find Integer
题解
费马大定理,简单说:满足a^n + b^n = c^n 这个等式,且a、b、c均为正整数的情况下,n只能为1和2。所以这个题就直接变成当n为1和2时的情况了。题目特判,写一种情况即可。n=1的时候,满足a+b=c即可,随便写。n=2的时候首先化简:
分为奇数和偶数情况。当a为奇数,可以这样推:
由于a为奇数,所以b必定为正整数,同时可得:
当a为偶数,可以这样推:
由于a为偶数,所以b必定为正整数,同时可得:
AC 代码
#include<iostream>
#include<vector>
#include<list>
#include<string>
#include<cmath>
#include<algorithm>
#include<map>
#include<set>
#include<utility>
#include<queue>
#include<sstream>
#include<iterator>
#include<math.h>
#include<malloc.h>
#include<string.h>
#include<stack>
#define TIME std::ios::sync_with_stdio(false)
#define LL long long
#define MAX 510
#define INF 0x3f3f3f3f
using namespace std;
int T;
int main() {
TIME;
scanf("%d", &T);
while (T--) {
LL n;
int a;
scanf("%lld%d", &n, &a);
if(n == 1){
printf("%d %d\n",1,a+1);
}else{
if(n == 2){
LL b,c;
if(a % 2 == 0){
b = (a*a/2 + 2)/2;
c = a*a/2 - b;
}else{
b = (a*a + 1)/2;
c = a*a - b;
}
if(b < c){
printf("%lld %lld\n",b,c);
}else{
printf("%lld %lld\n",c,b);
}
}else{
printf("-1 -1\n");
}
}
}
system("pause");
return 0;
}
1009 Tree and Permutation
题解
这个题跟树上距离有关,问题在于如何转换成为树上距离的问题。首先题目比较绕,大意是所有全排列后,到达每个结点的最短路的权值和。以题目给的第二个样例解释:
3个点全排列为:
1 2 3 w12 + w13
1 3 2 w13 + w12
2 1 3 w12 + w23
2 3 1 w23 + w12
......
像这样,最终求和。
我们就可以发现规律,全排列的情况下任意2点的距离总共出现了次,那么求和的答案就是次数乘上任意2点距离和,也就是树上距离和。那么利用树状dp求出以后做乘法就完事了。这个出现的次数比较难算,要这样分析。例如w12的出现次数,在以1开头中,出现了次,在2开头中,w21与w12是等价的,也出现了同样次数,所以是次。
这个题数据非常大,并且也要求对答案取模。这一点还是比较恶心的,感觉对这种需要取模的题,正常写能写出来,取模部分就经常错,并且还很难自己写数据测试。这个题就一直卡在一点,的取模,不能直接乘后再取模。所以应该在最初的时候利用num数组,算出所有阶乘,并且每次都要取模。这样预处理以后答案就正确了。
代码
#include<iostream>
#include<vector>
#include<list>
#include<string>
#include<cmath>
#include<algorithm>
#include<map>
#include<set>
#include<utility>
#include<queue>
#include<sstream>
#include<iterator>
#include<math.h>
#include<malloc.h>
#include<string.h>
#include<stack>
#define TIME std::ios::sync_with_stdio(false)
#define LL long long
#define MOD 1000000007
#define MAX 101000
#define INF 0x3f3f3f3f
using namespace std;
int N;
LL sum[MAX],dp[MAX],num[MAX];
struct node{
int to;
LL value;
};
vector<node> vec[MAX];
void init(){
memset(dp,0,sizeof(dp));
for(int i = 0;i <= N;i++){
vec[i].clear();
sum[i] = 1;
}
}
void tree_dp(int root,int father){
int len = vec[root].size();
for(int i = 0;i < len;i++){
int son = vec[root][i].to;
if(son == father) continue;
tree_dp(son,root);
LL value = vec[root][i].value;
sum[root] += sum[son];
dp[root] = (dp[root] + dp[son] + (sum[son]*(N - sum[son])*value)%MOD)%MOD;
}
}
int main() {
TIME;
num[1] = 1;
for(int i = 2;i < MAX;i++){
num[i] = (num[i-1]*i) % MOD;
}
while(scanf("%d",&N) != EOF){
init();
int a,b;
LL c;
for(int i = 0;i < N-1;i++){
scanf("%d%d%lld",&a,&b,&c);
vec[a].push_back(node{ b,c });
vec[b].push_back(node{ a,c });
}
tree_dp(1,0);
printf("%lld\n",((dp[1]*2)%MOD*num[N-1])%MOD);
}
system("pause");
return 0;
}