2018 CCPC 网络赛 (待更新) HDU 6438 ~ 6447
莫干山半日游,体验略差啊、、
AC情况
题号 | 1001 | 1002 | 1003 | 1004 | 1005 | 1006 | 1007 | 1008 | 1009 | 1010 |
---|---|---|---|---|---|---|---|---|---|---|
√ | X | √ | √ | X | X | X | X | √ | √ |
(1001) HDU 6438 Buy and Resell
题目链接
题意:
商人能在N个地方以 ai a i 的价格买入或卖出商品,在每个地方只能做一次交易。要求最大的收益,同时最小化交易次数。
思路:
贪心。用优先队列维护一个可买入的序列以及一个已经卖出的队列(还可以反悔tao),分类讨论即可。
AC代码:
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <vector>
#include <stack>
#include <bitset>
using namespace std;
#define FSIO ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define DEBUG(a) cout<<"DEBUG: "<<(a)<<endl;
#define ll long long
#define pb push_back
const int MAXN = 200005;
const ll MOD = 1e9+7;
const int INF = 1e9+7;
int _;
using namespace std;
priority_queue<ll, vector<ll>, greater<ll>> sell;
priority_queue<ll, vector<ll>, greater<ll>> resell;
int main()
{
//freopen("input","r",stdin);
//freopen("output","w+",stdout);
cin>>_;
while(_--)
{
int N;
scanf("%d",&N);
ll ans = 0LL;
ll times = 0LL;
ll item;
while(!sell.empty()) sell.pop();
while(!resell.empty()) resell.pop();
for(int i=1;i<=N;++i)
{
scanf("%I64d",&item);
if(!resell.empty())
{
ll least_sold = resell.top();
if(!sell.empty()&&sell.top()<least_sold&&least_sold<item)
{
times += 2;
ans += item;
resell.push(item);
sell.pop();
}
else if(least_sold<item)
{
resell.pop();
ans -= least_sold*2LL;
ans += item;
sell.push(least_sold);
resell.push(item);
}
else if(!sell.empty()&&sell.top()<item)
{
times += 2;
ans += item;
resell.push(item);
sell.pop();
}
else
{
sell.push(item);
ans -= item;
}
}else if(!sell.empty()&&sell.top()<item)
{
times += 2;
ans += item;
resell.push(item);
sell.pop();
}else
{
sell.push(item);
ans -= item;
}
}
while(!sell.empty()) ans += sell.top(), sell.pop();
printf("%I64d %I64d\n",ans,times);
}
return 0;
}
(1003) HDU 6440 Dream
题目链接
题意:
对一个质数P,对小于P的非负数定义一种乘法和加法运算,使得其满足封闭性,且对于存在一个数q使得 {qk|0<k<p}={k|0<k<p} { q k | 0 < k < p } = { k | 0 < k < p } ,且有 (m+n)p=np+mp ( m + n ) p = n p + m p 。
思路:
易得,对于一个质数p,模p意义下 2k%p 2 k % p 可以构成一个 {k|0<k<p} { k | 0 < k < p } ,不妨将乘法定义为 i∗j=(i∗j)%p i ∗ j = ( i ∗ j ) % p ,同时为了简便将加法定义为 i+j=i i + j = i ,显然满足条件。
AC代码:
// by Yongqiang Chen
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <vector>
#include <stack>
#include <bitset>
using namespace std;
#define FSIO ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define DEBUG(a) cout<<"DEBUG: "<<(a)<<endl;
#define ll long long
#define pb push_back
const int MAXN = 100005;
const ll MOD = 1e9+7;
const int INF = 1e9+7;
int _;
using namespace std;
int main()
{
//freopen("input","r",stdin);
//freopen("output","w+",stdout);
cin>>_;
while(_--)
{
int P;
scanf("%d",&P);
for(int i=0;i<P;++i)
{
for(int j=0;j<P-1;++j)
printf("%d ",i);
printf("%d\n",i);
}
for(int i=0;i<P;++i)
{
for(int j=0;j<P-1;++j)
printf("%d ",(i*j)%P);
printf("%d\n",(i*(P-1))%P);
}
}
return 0;
}
(1004) Find Integer
题目链接:无补题链接
题意:
给定n, a,解方程 an+bn=cn a n + b n = c n 输出b和c。
思路:
n大于3无解,讨论n为2和1的情况即可。
AC代码:
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
long long a, b, c;
int t;
cin >> t;
long long n;
while(t--){
scanf("%lld%lld", &n, &a);
if(n == 0){
printf("-1 -1\n");
}else if(n == 1){
printf("1 %lld\n", a+1);
}else if(n > 2){
printf("-1 -1\n");
}else{
long long mul = a*a;
if(mul & 1){
printf("%lld %lld\n", (mul-1)/2, (mul+1)/2);
}else{
b = (mul-4)/4;
c = b+2;
printf("%lld %lld\n", b, c);
}
}
}
return 0;
}
(1009) HDU 6446 Tree and Permutation
题目链接
题意:
给一棵N个点的树,对应于一个长为N的全排列,对于排列的每个相邻数字a和b,他们的贡献是对应树上顶点a和b的路径长,求所有排列的贡献和。
思路:
随手画几颗树,统计一下树上所有点对对于答案的贡献,发现存在规律。
即
a[2]=2 a [ 2 ] = 2
i>=3时,a[i]=a[i−1]∗(i−1), i >= 3 时 , a [ i ] = a [ i − 1 ] ∗ ( i − 1 ) ,
那么只需要DFS一遍树上所有点对路径之和再乘上a[N]即可。DFS时,每条边对路径和的贡献是连接该边左右子树大小之积。
AC代码:
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <vector>
#include <stack>
#include <bitset>
using namespace std;
#define FSIO ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define DEBUG(a) cout<<"DEBUG: "<<(a)<<endl;
#define ll long long
#define pb push_back
const int MAXN = 100005;
const ll MOD = 1e9+7;
const int INF = 1e9+7;
int _;
using namespace std;
int N;
int head[MAXN];
int curedgeno;
struct Edge{
int u, v, w;
int next;
Edge(int u=0, int v=0, int w=0, int next=-1): u(u), v(v), w(w), next(next) {}
}edge[MAXN<<1];
void init()
{
memset(head,-1,sizeof(head));
curedgeno = 0;
}
void add_edge(int u, int v, int w)
{
++curedgeno;
edge[curedgeno] = Edge(u,v,w);
edge[curedgeno].next = head[u];
head[u] = curedgeno;
}
ll num[MAXN];
int mk[MAXN];
ll tot_sum;
// return the sum of sub tree
ll dfs(int u, int fa)
{
mk[u] = 1;
ll cnt = 1;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v = edge[i].v;
if(!mk[v]&&v!=fa)
{
ll tmp = dfs(v,u);
cnt += tmp;
tot_sum = (tot_sum+tmp*(N-tmp)%MOD*(ll)edge[i].w%MOD)%MOD;
}
}
return cnt;
}
int main()
{
//freopen("input","r",stdin);
//freopen("output","w+",stdout);
num[1] = 0;
num[2] = 2;
num[3] = 4;
for(int i=4;i<MAXN;++i)
num[i] = num[i-1]*(ll)(i-1)%MOD;
while(scanf("%d",&N)!=EOF)
{
init();
int u, v, w;
memset(mk,0,sizeof(mk));
for(int i=1;i<N;++i)
{
scanf("%d%d%d",&u,&v,&w);
add_edge(u,v,w);
add_edge(v,u,w);
}
tot_sum = 0LL;
dfs(1,-1);
//cout<<tot_sum<<endl;
printf("%lld\n",tot_sum*num[N]%MOD);
}
return 0;
}
(1010) HDU 6447 YJJ’s Salesman
题目链接
题意:
二维平面上N个点,从(0,0)出发到(1e9,1e9),每次只能往右,上,右上三个方向移动,
该N个点只有从它的左下方格点可达,此时可获得收益。求该过程最大收益。
思路:
首先联想到一个DP,设
dp[i][j]
d
p
[
i
]
[
j
]
为到达即对每个点
(i,j)
(
i
,
j
)
,到达该点的最大收益为
max(dp[i′][j′]+val[i][j])
m
a
x
(
d
p
[
i
′
]
[
j
′
]
+
v
a
l
[
i
]
[
j
]
)
,复杂度为
O(N2)
O
(
N
2
)
,不管是时间还是空间都不允许。
不妨利用坐标信息,将所有点离散化之后,将x作为第一关键字从小到大,y作为第二关键字从大到小排序,此时维护一个
dp[i]
d
p
[
i
]
表示到
y=i
y
=
i
时可以获得的最大收益,那么有
dp[i]←max(dp[i[,dp[j]+val) d p [ i ] ← m a x ( d p [ i [ , d p [ j ] + v a l )
因为x已经按从小到大排好序了,y也是从大到小更新的,故保证了可达性。
对于每次更新,可以用线段树或者树状数组维护最大值,此时算法复杂度 O(NlogN) O ( N l o g N )
AC代码:
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <vector>
#include <stack>
#include <bitset>
using namespace std;
#define FSIO ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define DEBUG(a) cout<<"DEBUG: "<<(a)<<endl;
#define ll long long
#define pb push_back
const int MAXN = 200005;
const ll MOD = 1e9+7;
const int INF = 1e9+7;
int _;
using namespace std;
struct Point{
int x, y, w;
Point() {}
Point(int _x, int _y, int _w):x(_x),y(_y),w(_w) {}
void read()
{
scanf("%d%d%d",&x,&y,&w);
}
void show()
{
printf("%d %d\n",x,y);
}
}points[MAXN];
bool operator<(const Point& a, const Point& b)
{
return a.x==b.x?a.y>b.y:a.x<b.x;
}
int N;
// Discretization
int hashx[MAXN], hashy[MAXN];
void gomapping()
{
for(int i=1;i<=N;++i)
{
hashx[i] = points[i].x;
hashy[i] = points[i].y;
}
sort(hashx+1,hashx+1+N);
sort(hashy+1,hashy+1+N);
int cntx = unique(hashx+1,hashx+1+N) - hashx;
int cnty = unique(hashy+1,hashy+1+N) - hashy;
for(int i=1;i<=N;++i)
{
points[i].x = lower_bound(hashx+1,hashx+1+cntx,points[i].x) - hashx;
points[i].y = lower_bound(hashy+1,hashy+1+cnty,points[i].y) - hashy;
}
//for(int i=1;i<=N;++i) points[i].show();
}
int dp[MAXN];
int tree[MAXN];
inline int lowbit(int x) { return x&-x; }
void update(int pos, int val)
{
while(pos <= N)
{
tree[pos] = dp[pos];
for(int i=1;i<lowbit(pos);i<<=1)
tree[pos] = max(tree[pos],tree[pos-i]);
pos += lowbit(pos);
}
}
int query(int l, int r)
{
int ans = 0;
while(r>=l)
{
ans = max(ans,dp[r]);
if(l==r) break;
for(--r;r-l>=lowbit(r);r-=lowbit(r))
ans = max(ans,tree[r]);
}
return ans;
}
int main()
{
//freopen("input","r",stdin);
//freopen("output","w+",stdout);
cin>>_;
while(_--)
{
scanf("%d",&N);
for(int i=1;i<=N;++i) points[i].read();
sort(points+1,points+1+N);
gomapping();
int cur = 1;
memset(tree,0,sizeof(tree));
memset(dp,0,sizeof(dp));
while(cur<=N)
{
int curx = points[cur].x;
while(cur<=N&&(curx = points[cur].x))
{
dp[points[cur].y] =
max(dp[points[cur].y],
query(1,points[cur].y-1)+points[cur].w);
update(points[cur].y,dp[points[cur].y]);
cur++;
}
}
int ans = 0;
for(int i=1;i<=N;++i)
ans = max(ans,dp[i]);
printf("%d\n",ans);
}
return 0;
}