CCPC-Wannafly Winter Camp Day1 (Div 2)

52 篇文章 0 订阅
20 篇文章 0 订阅

部分题,

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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值