码迷,mamicode.com
首页 > 其他好文 > 详细

Codeforces Round #592 (Div. 2)

时间:2019-11-23 22:13:44      阅读:49      评论:0      收藏:0      [点我收藏+]

标签:ace   target   pop   fine   表示   over   fas   枚举   lin   

https://codeforces.com/contest/1244/problem/C

求出满足以下公式的

给出n,p,w,dn,p,w,d,求解:

x⋅w+y⋅d=p
x+y≤n
首先是w>d的
接下来我们可以分析我们用暴力枚举来枚举一个然后来判断另一个对吧,但是呢纯暴力是妥妥tle
我们又知道w>d,那么y<w,
因为如果y=w,那么相当于wdw∗d,然后取了wd,那么不如取dw更优。
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(ll i=(a);i<=(b);++i)
#define dep(i,a,b) for(ll i=(a);i>=(b);--i)
#define pb push_back
typedef long long ll;
const int maxn=(int)2e5+100;
const int mod=(int)1e9+7;
ll n,p,d,w;
int main(){
    scanf("%lld%lld%lld%lld",&n,&p,&w,&d);
    if(n*w<p) return puts("-1"),0;
    rep(i,0,w){
        if((p-i*d)%w==0){
            ll x=(p-1ll*i*d)/w,y=i;
            if(x+y>n) return puts("-1"),0;
            return printf("%lld %lld %lld",x,y,n-x-y),0;
        }
        if(i*d>p) break;
    }
    return puts("-1"),0;
}

 https://codeforces.com/contest/1244/problem/D

给出三行数据,第一行表示选择颜色1的各个顶点的花费,第二行表示颜色2...

然后每三个相邻点颜色不能一样

容易发现只有链的情况合法,链的情况就很简单了。
因为颜色个数较少,所以直接枚举颜色排列染色就行。

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define dep(i,a,b) for(int i=(a);i>=(b);--i)
#define pb push_back
typedef long long ll;
const int maxn=(int)2e5+100;
const int mod=(int)1e9+7;
int n,ind[maxn],pos=1,pp=1,id[10][maxn];
ll c[4][maxn];
vector<int> g[maxn<<1];
ll dfs(int pos,int st,int fa,int col1,int col2){
	ll ans=0;int col;
	rep(i,1,3) if(i!=col1&&i!=col2) col=i;
	id[pos][st]=col;
	if((int)g[st].size()==1) return c[col-1][st];
	rep(i,0,1) if(g[st][i]!=fa) return c[col-1][st]+dfs(pos,g[st][i],st,col2,col);
 
}
int main(){
	scanf("%d",&n);
	rep(i,1,n) scanf("%lld",&c[0][i]);
	rep(i,1,n) scanf("%lld",&c[1][i]);
	rep(i,1,n) scanf("%lld",&c[2][i]);
	rep(i,1,n-1){
		int u,v;scanf("%d%d",&u,&v);
		g[u].pb(v);g[v].pb(u);
		ind[u]++;ind[v]++;
	}
	int num=0,st=0,ed=0;
	rep(i,1,n){
		if(ind[i]==1){
			num++;
			if(st) ed=i;
			else st=i;
		}
		else if(ind[i]>2) return puts("-1"),0;
	}
	if(num!=2) return puts("-1"),0;
	ll ans=(ll)1e18;
	int st2=g[st][0],st3;
	rep(i,0,1) if(g[st2][i]!=st) st3=g[st2][i];
	rep(i,1,3) rep(j,1,3) if(i!=j){
		pos++;
		id[pos][st]=i;id[pos][st2]=j;
		ll tmp=c[i-1][st]+c[j-1][st2]+dfs(pos,st3,st2,i,j);
		if(ans>tmp) ans=tmp,pp=pos;
	}
	printf("%lld\n",ans);
	rep(i,1,n) printf("%d ",id[pp][i]);
	puts("");
}

  https://codeforces.com/contest/1244/problem/E

  • 题意: 一个序列,每次可以选一个数+1或-1,可以操作k次,求最小化最大减最小的差.
  • 思路: 因为差值是有单调性的(如果差值d在序列里可以在变化操作k内实现,那么我们可以花费更多操作次数缩小d继续查找,如果不能说明d太小k次操作不够支撑,那我们可以增大d继续查找),所以二分差,肯定有一个a[i]是不变的(肯定的嘛使差值最小你锁定两个数字其中一个不用变,变另外一个就行了),check时就枚举a[i]不变(上界下界枚举两次),然后lower_bound找到比下界小的,要加到下界,upper_bound找到比上界大的,要减到上界,算操作次数是否满足小于k.
#include <bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
// #define Local
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 1e5 + 5;
 
ll n, k;
int a[N];
ll sum[N];
 
bool chk(int d) {
    for(int i = 1; i <= n; i++) {
        int low = lower_bound(a + 1, a + n + 1, a[i]) - a - 1;
        int high = upper_bound(a + 1, a + n + 1, a[i] + d) - a;
        ll tot = 1ll * low * a[i] - sum[low] + sum[n] - sum[high - 1] - 1ll * (n - high + 1) * (a[i] + d);
        if(tot <= k) return true;
    }
    for(int i = 1; i <= n; i++) {
        int high = upper_bound(a + 1, a + n + 1, a[i]) - a;
        int low = lower_bound(a + 1, a + n + 1, a[i] - d) - a - 1;
        ll tot = 1ll * low * (a[i] - d) - sum[low] + sum[n] - sum[high - 1] - 1ll * (n - high + 1) * a[i];
        if(tot <= k) return true;
    }
    return false;
}
 
void run() {
    int res=0;
    for(int i = 1; i <= n; i++) cin >> a[i];
    sort(a + 1, a + n + 1);
    for(int i = 1; i <= n; i++) sum[i] = sum[i - 1] + a[i];
    int l = 0, r = 1e9 + 1, mid;
    while(l <=r) {
        mid = (l + r) >> 1;
        if(chk(mid)) res=mid,r=mid-1;
        else l= mid+1;
    }
    cout << res<< ‘\n‘;
}
 
int main() {
    while(cin >> n >> k) run();
    return 0;
}

  https://codeforces.com/contest/1244/problem/G


sum=∑i=max(pi,qi)≤k,sum要最大

最小的sum肯定是(n)*(n+1)/2;

考虑将第一个排列顺序排放。
然后考虑第二个排列刚开始也是顺序排放的。
然后考虑交换位置视为元素左移和元素右移。
显然,元素右移不会对答案产生影响。
但是元素左移,左移几个位置它就产生多少贡献。
那么显然可以发现这个变化是连续的,直接贪心即可。

#pragma GCC optimize("Ofast,unroll-loops,no-stack-protector,fast-math")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#include <bits/stdc++.h>
#define fi first
#define se second
#define endl "\n" 
using namespace std;
using db = double;
using ll = long long;
using ull = unsigned long long; 
using pII = pair <int, int>;
using pLL = pair <ll, ll>;
constexpr int mod = 1e9 + 7;
template <class T1, class T2> inline void chadd(T1 &x, T2 y) { x += y; while (x >= mod) x -= mod; while (x < 0) x += mod; } 
template <class T1, class T2> inline void chmax(T1 &x, T2 y) { if (x < y) x = y; }
template <class T1, class T2> inline void chmin(T1 &x, T2 y) { if (x > y) x = y; }
inline int rd() { int x; cin >> x; return x; }
template <class T> inline void rd(T &x) { cin >> x; }
template <class T> inline void rd(vector <T> &vec) { for (auto &it : vec) cin >> it; }  
#define dbg(x...) do { cout << "\033[32;1m" << #x << " -> "; err(x); } while (0) 
void err() { cout << "\033[39;0m" << endl; } 
template <class T, class... Ts> void err(const T& arg, const Ts&... args) { cout << arg << ‘ ‘; err(args...); }
template <template<typename...> class T, typename t, typename... A> 
void err(const T <t> &arg, const A&... args) { for (auto &v : arg) cout << v << ‘ ‘; err(args...); }
inline void pt() { cout << endl; } 
template <class T, class... Ts> void pt(const T& arg, const Ts&... args) { cout << arg << ‘ ‘; pt(args...); }
template <template<typename...> class T, typename t, typename... A> 
void pt(const T <t> &arg, const A&... args) { for (auto &v : arg) cout << v << ‘ ‘; pt(args...); }
ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; }
inline ll qpow(ll base, ll n) { ll res = 1; while (n) { if (n & 1) res = res * base % mod; base = base * base % mod; n >>= 1; } return res; }
//head
constexpr int N = 1e6 + 10;
int n, a[N]; ll k; 
void run() {
    ll base = 1ll * n * (n + 1) / 2;
    if (base > k) return pt(-1);
    for (int i = 1; i <= n; ++i) a[i] = i;
    ll remind = k - 1ll * n * (n + 1) / 2;
    int low = 1;
    for (int i = n; i >= 1 && i > low; --i) {
        if (i - low <= remind) {
            remind -= i - low;
            swap(a[i], a[low]);
            ++low;
        } else {
            swap(a[i], a[i - remind]);
            remind = 0;
            break;
        }
    }
    pt(k - remind);
    for (int i = 1; i <= n; ++i) cout << i << " \n"[i == n];
    for (int i = 1; i <= n; ++i) cout << a[i] << " \n"[i == n];
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr); cout.tie(nullptr);
    cout << fixed << setprecision(20);
    while (cin >> n >> k) run();
    return 0;
}

  

 

 

 

Codeforces Round #592 (Div. 2)

标签:ace   target   pop   fine   表示   over   fas   枚举   lin   

原文地址:https://www.cnblogs.com/hgangang/p/11919758.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!