Buy and Resell(优先队列)
题意:按顺序走过N个城市,每个城市有对应的货物价值,可以买入或者卖出,求最多利润及获得最大利润的最短交易次数。
题解:我们假设在每一个城市都买入,维护一个升序的优先队列,里面标识的是买入的货物价值,所以每次push进去,并枚举每个城市的货物价值,如果大于队列队首元素,则给结果加上差值(记作x1),并次数加一,在这里需要考虑到可能后面有货物价值大于此次枚举的值,所以要再将这次枚举的值push进去,等到它为队首且小于新枚举的值时,结果加上差值(记作x2),这时可以想到x1 + x2的值就等于x1那次没有卖出,在这次再卖出货物的价值,所以,次数减一。
优先对列,map
参考自大牛博文:https://blog.youkuaiyun.com/Tony5t4rk/article/details/82056768
代码如下:
#include<cstdio>
#include<functional>
#include<queue>
#include<vector>
#include<map>
using namespace std;
int main()
{
int t, n, x;
scanf("%d",&t);
while(t--)
{
long long ans = 0;
int time = 0;
priority_queue<int, vector<int>, greater<int> > p; //升序
map<int, int> vis;
scanf("%d",&n);
while(n--)
{
scanf("%d",&x);
p.push(x);
if(p.top() < x)
{
time ++;
ans += x - p.top();
if(vis[p.top()])
{
time --;
vis[p.top()] --;
}
vis[x] ++;
p.pop();
p.push(x);
}
}
printf("%lld %d\n",ans, time * 2);
}
return 0;
}
Tree and Permutation:
题意:N!中排列求出距离和,距离定义为:假设一个排列为a1,a2,a3,则距离就是a1a2+a2a3,最后对所有排列求和。
解析:贡献思想,选中其中一边,则边的左边是a个结点,则右边是b个结点,那么左边和右边连接的方式就有a*b种,左右交换又是b*a,然后除去这条边的两个节点之外,剩下(n-2)个节点构成(n-2)!种排列,有(n-1)个空,插空法,那么结果就是2*a*(n-a)*len*(n-2)!*(n-1)。
代码如下:
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
const int maxn = 1e5 + 10;
const ll mod = 1e9 + 7;
int n, cnt;
int head[maxn], num[maxn];
ll dp[maxn], fac[maxn];
ll ans;
struct node
{
int to, next;
ll w;
}edge[maxn * 2];
void add(int u, int v, ll w)
{
++ cnt;
edge[cnt].to = v;
edge[cnt].next = head[u];
edge[cnt].w = w;
head[u] = cnt;
}
void getfac()
{
fac[0] = 1;
fac[1] = 1;
for(int i = 2; i < maxn; ++ i)
{
fac[i] = i * fac[i-1] % mod;
}
}
void dfs(int u, int fa)
{
dp[u] = 1;
for(int i = head[u]; i ;i = edge[i].next)
{
int v = edge[i].to;
if(v == fa) continue;
dfs(v, u);
dp[u] += dp[v];
ans = (ans + dp[v] * (n - dp[v]) % mod * edge[i].w % mod) % mod;
}
}
int main()
{
getfac();
while(~scanf("%d",&n))
{
memset(num, 0, sizeof(num));
memset(head, 0, sizeof(head));
memset(dp, 0, sizeof(dp));
cnt = 0;
for(int i = 0; i < n - 1; ++ i)
{
int l, r;
ll w;
scanf("%d%d%lld",&l,&r,&w);
num[l] ++; num[r] ++;
add(l, r, w);
add(r, l, w);
}
ans = 0;
for(int i = 1; i <= n; ++ i)
{
if(num[i] == 1)
{
dfs(i, 0);
break;
}
}
ans = ans * 2 % mod * fac[n-1] % mod;
printf("%lld\n",ans);
}
return 0;
}
Dream
题意:重新构造加法和乘法,使当p为质数时(m+n)^p = m^p + n^p 成立。输出
解析:
代码如下:
#include<cstdio>
using namespace std;
int main()
{
int t, p;
scanf("%d",&t);
while(t--)
{
scanf("%d",&p);
for(int i = 0; i < p; ++ i)
{
for(int j = 0; j < p; ++ j)
{
printf("%d ", (i + j) % p);
}
printf("\n");
}
for(int i = 0; i < p; ++ i)
{
for(int j = 0; j < p; ++ j)
{
printf("%d ", (i * j) % p);
}
printf("\n");
}
}
return 0;
}