部分题,

C题:​​https://www.cometoj.com/contest/7/problem/C?problem_id=94​

数论

如果AB不互质,那么肯定当n==2时 有解。不会证明,拿小本本记下来;

/*
如果AB不互质 那么就肯定当n==2 有解
*/
#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll gcd(ll a,ll b)
{
return b==0 ? a : gcd(b, a % b);
}
int main()
{
int t;
ll A, B;
cin >> t;
while(t--)
{
cin >> A >> B;
if(gcd(A,B)==1)
{
cout << "1" << endl
<< A << " " << B << endl;
}else
{
cout << "2" << endl;
for (ll i = 2, j = 3; i < A && j < B;i++,j++)
{
if(gcd(i,j)==1&&gcd(A-i,B-j)==1)
{
cout << i << " " << j << endl;
cout << A - i << " " << B - j << endl;
break;
}
}
}
}
return 0;
}

J题 ​​https://www.cometoj.com/contest/7/problem/J?problem_id=101​

一个富商收购村民的宝物,收购人家的宝物得给人家钱啊,并且有点村民手里有多个宝物,最后求富商收购的宝物数量大于村民的宝物数量的最小代价(富商付的钱)。。。(富商都这么有钱了,为什么不都买下来~);

J题后来想多了,(我现在怎么什么题都能想到dp,而且dp我也不会) 后来学习了一下别人的题解

正解:枚举最后拥有的宝物数量k,将拥有k个以上的宝物的人手里收购宝物使得宝物数量低于k,如果最后收购的宝物不足k个的话,就从宝物里选价值最小的。

/*
枚举最后拥有的宝物数量k
将拥有k个以上宝物的人手里收购多于k的最小价值宝物
如果最后不足k个的话再从宝物里选择价值最小的
即可。
*/
#include <bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f3f3f3f
#define Max 1111
using namespace std;
struct Goods
{
int id;//编号
int val;//价值
bool operator < (const Goods &x) const{
return val < x.val;
}
};
vector<Goods> x;//m个宝物的信息
vector<Goods> y[Max];//n个人拥有的宝物情况
int vis[Max];//标记宝物是否被买
int main()
{
ios::sync_with_stdio(0);
int n, m, a, c;
cin >> n >> m;
for (int i = 1; i <= m; i++)
{
cin >> a >> c; //价格 拥有宝物居民编号
x.push_back({i, a});
y[c].push_back({i, a});
}
sort(x.begin(), x.end()); //小的在前
for (int i = 1;i<=n;i++)
{
sort(y[i].begin(), y[i].end());
}
// vector<Value>::iterator it;
// for (it = x.begin(); it != x.end();it++)
// {
// cout << "--> " << (*it).id << " " << (*it).val << endl;
// }
ll ans = inf;///inf必须大大大
for (int k = 1; k <= m;k++)
{
ll ans1 = 0;
int cnt = 0;
memset(vis, 0, sizeof(vis));
for (int i = 1; i <= n;i++)
{
if(y[i].size()>=k){
for (int j = 0; j <= y[i].size() - k;j++)
{
ans1 += y[i][j].val;
cnt++;
vis[y[i][j].id] = 1;
}
}
}
/*如果不足k个,这一步是保证最后得到了k个宝物*/
for (int i = 0; i < x.size() && cnt < k; i++)
{
if (!vis[x[i].id])
{
vis[x[i].id] = 1;
ans1 += x[i].val;
cnt++;
}
}
ans = min(ans1, ans);
}
cout << ans << endl;
return 0;
}

F题  ​​https://www.cometoj.com/contest/7/problem/F?problem_id=97​

这道题我又又又又想到了dp,啧啧

题意是:n座山,并且每座山都有一个高度,你爬高山要消耗体力,你爬底山要增加体力,爬山的时候体力值不能小于0,山和山之间也有个距离,你可以降低删的高度L,则代价是 L*L,你在1号山,你要去n号山,求最小代价(即降低山的高度的总代价+走过的路程)

思路:刚开始在1号山,所以体力值为k+h[1],对于比1高的山,要砍的话就要砍到 k+h[1] 为止 ,将砍山的消耗(h[x]-(h[1]+k))^2加到边的权值上,然后dijkstra;

/*
比1号山低的山我们其实是不需要关注的,因为虽然下山增加体力,
但是在上山的过程中有抵消了。
*/
#include <bits/stdc++.h>
#define ll long long
#define Max 2200000
#define inf 0x3f3f3f3f
#define pii pair<ll,ll>
using namespace std;
ll h[Max], vis[Max];
ll dis[Max];
int n, m, s, t, k;
vector<pair<int, ll> > edge[Max];
void init()
{
memset(vis, 0, sizeof(vis));
for (int i = 0; i <= n; i++)
{
edge[i].clear();
}
memset(dis, inf, sizeof(dis));
}
/*
priority_queue 默认降序
所以存距离的时候存该距离的负数
*/
void dijkstra()
{
dis[s] = 0;
priority_queue<pii> q;
q.push({-dis[s], s});
while(!q.empty())
{
int cur = q.top().second;
// cout << "len: " << q.top().first << endl;
q.pop();
if(vis[cur])
continue;
vis[cur] = 1;
for (int i = 0; i < edge[cur].size();i++)
{
int nex = edge[cur][i].first;
// cout << "***->> " << edge[cur][i].second<< endl;
if (!vis[nex] && dis[nex] > dis[cur] + edge[cur][i].second)
{
dis[nex] = dis[cur] + edge[cur][i].second;
q.push({-dis[nex], nex});
}
}
}
}
int main()
{
ios::sync_with_stdio(0);
cin >> n >> m >> k;
init();
for (int i = 1; i <= n; i++)
{
cin >> h[i];
}
k += h[1]; //初始
int a, b;
ll x;
while (m--)
{
cin >> a >> b >> x;
if (h[b] >= k)
{
edge[a].push_back({b, x + (h[b] - k) * (h[b] - k)});
}
else
{
edge[a].push_back({b, x});
}
if (h[a] >= k)
{
edge[b].push_back({a, x + (h[a] - k) * (h[a] - k)});
}
else
{
edge[b].push_back({a, x});
}
}
s = 1;
t = n;
dijkstra();
cout << dis[t] << endl;

return 0;
}

C题:​​https://www.cometoj.com/contest/7/problem/B?problem_id=93​

这道题我也想学,这应该就是dp了,先占个坑。

dp i  j k  表示当前ij位置最多得到k个糖果,通过k-1秒5个位置转移得到(i,j,k)

 

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
#define Max 11111
using namespace std;
int n,m,c,xs,ys,xt,yt;
int dp[20][20][Max];
int T[20][20];
int main() {
scanf("%d%d%d",&n,&m,&c);
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)scanf("%d",&T[i][j]);
scanf("%d%d%d%d",&xs,&ys,&xt,&yt);
memset(dp,-inf,sizeof(dp));
dp[xs][ys][0]=0;
for(int k=1; k<Max; k++)
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++) {
dp[i][j][k]=max(dp[i-1][j][k-1],max(max(max(dp[i][j+1][k-1],dp[i+1][j][k-1]),dp[i][j-1][k-1]),dp[i][j][k-1]))+(k%T[i][j]==0?1:0);
}
int maxx=-1;
for(int i=0; i<Max; i++)
if(dp[xt][yt][i]>=c) {
maxx=i;
break;
}
printf("%d\n",maxx);
return 0;
}