https://codeforces.com/contest/1244/problem/C
求出满足以下公式的
给出n,p,w,dn,p,w,d,求解:
#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 ll long long const int N = 1e5+10; int n; vector<int> cost[3]; vector<vector<int> > adj; vector<int> p,perm ={0,1,2},best_perm,ans; int main(){ ios::sync_with_stdio(0);cin.tie(0); int u,v,root; cin >> n; for(int i=0;i<3;++i){ cost[i].resize(n); for(int j=0;j<n;++j) cin >> cost[i][j]; } adj.assign(n,{}); for(int i=0;i<n-1;++i){ cin >> u >> v; u--; v--; adj[u].push_back(v); adj[v].push_back(u); } for(int i=0;i<n;++i){ if(adj[i].size()>2){ cout <<"-1\n"; return 0; }else if(adj[i].size()==1){ root = i; } } p.push_back(root); while(p.size()<n){ v = p.back(); for(auto nx:adj[v]){ if(p.size()==1||nx!=p[p.size()-2]){ p.push_back(nx); break; } } } ll best = 1LL<<62; do{ ll score = 0; for(int i=0;i<n;++i) score += cost[perm[i%3]][p[i]]; if(score<best){ best_perm = perm; best = score; } }while(next_permutation(perm.begin(),perm.end())); cout << best << '\n'; ans.resize(n); for(int i=0;i<n;++i) ans[p[i]] = best_perm[i%3]; for(int i=0;i<n;++i) cout << ans[i]+1<<' '; cout <<'\n'; return 0; }
#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; }
F
给你一个环,由wb两个字符构成,每次会进行一次操作所有位置的字符如果左右两个位置相同,就变成这个字符;例如wbw变成www。问你进行k次会变成什么
1、连续的W或者B不论执行多少次操作,都不会改变。
2、连续的形如WBWB的子串,每次操作会翻转一次。
所以我们先处理出连续的字符串的两端点,然后再处理夹在他们中间的不连续的字符串
这段不连续的字符串有什么特点?你总不可能模拟,他转一次你也一个个转一次把;
我们可以发现两个端点会被同化成左右边的连续字符串的字符,然后中间的呢?我们要一个个反转?
不需要我们假设一条无限长的不连续wbwbwbw......你会发现中间这段随着的次数的增加只不过是在像01一样变0变1地不断重复,而左右两端随着次数的增加不断同化到该不连续字符串地左右两边连续字符串;
所以我们只需每次就处理一次不连续地然后把修改的新的放进容器;
当然要特殊处理下当出现的不连续只剩下夹在中间一个字符而已,就特判一下,如果字符左右两边相对就变为左右字符
#include <bits/stdc++.h> #define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0) #define N 200005 #define M 100005 #define INF 0x3f3f3f3f #define mk(x) (1<<x) // be conscious if mask x exceeds int #define sz(x) ((int)x.size()) #define upperdiv(a,b) (a/b + (a%b>0)) #define mp(a,b) make_pair(a, b) #define endl '\n' #define lowbit(x) (x&-x) using namespace std; typedef long long ll; typedef double db; /** fast read **/ template <typename T> inline void read(T &x) { x = 0; T fg = 1; char ch = getchar(); while (!isdigit(ch)) { if (ch == '-') fg = -1; ch = getchar(); } while (isdigit(ch)) x = x*10+ch-'0', ch = getchar(); x = fg * x; } template <typename T, typename... Args> inline void read(T &x, Args &... args) { read(x), read(args...); } int n, k; bool vis[N]; int posl[N], posr[N]; string s; void input() { read(n, k); cin >> s; for (int i = 0; i < n; i++) { if (i == 0) posl[i] = n-1; else posl[i] = i-1; if (i == n-1) posr[i] = 0; else posr[i] = i+1; vis[i] = false; } } struct SNode{ int p; int type; // l1, r2; bool operator < (const SNode& x) const { return p < x.p; } }; int main() { input(); queue <SNode> ps, tmpps; for (int l = 0; l < n; l++) { int r = l; while (r+1 < n && s[r+1] == s[r]) { ++r; } if (r-l+1 >= 2) { for (int i = l; i <= r; i++) vis[i] = true; ps.push(SNode{l, 1}); ps.push(SNode{r, 2}); l = r; } } if (!vis[0] && !vis[n-1] && s[0] == s[n-1]) { ps.push(SNode{n-1, 1}); ps.push(SNode{0, 2}); vis[0] = vis[n-1] = true; } /** 000000pr0000pl000 **/ bool can_reverse = false; for (int i = 1; i <= k; i++, can_reverse = !can_reverse) { if (ps.empty()) break; while (!ps.empty()) { SNode tmpr = ps.front(); ps.pop(); if (tmpr.type == 1) { ps.push(tmpr); continue; } SNode tmpl = ps.front(); ps.pop(); int pl = tmpl.p, pr = tmpr.p; if (posl[pl] != pr && posl[posl[pl]] != pr) { int prr = posr[pr], pll = posl[pl]; s[prr] = s[pr]; vis[prr] = true; tmpps.push(SNode{prr, 2}); s[pll] = s[pl]; vis[pll] = true; tmpps.push(SNode{pll, 1}); } else if (posl[posl[pl]] == pr) { int p = posl[pl]; vis[p] = true; if (s[pl] == s[pr]) s[p] = s[pl]; else if (can_reverse) {///16 5 WBBBBWBBBBBBWBBW
if (s[p] == 'B') s[p] = 'W'; else if (s[p] == 'W') s[p] = 'B'; } } } while (!tmpps.empty()) { ps.push(tmpps.front()); tmpps.pop(); } } if (can_reverse) { for (int i = 0; i < n; i++) { if (!vis[i]) { if (s[i] == 'B') s[i] = 'W'; else if (s[i] == 'W') s[i] = 'B'; } } } cout << s << endl; return 0; } /* 1 BWBBWW */
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; }