Codeforces Round #379 (Div. 2)
B ~~
C
对于第二种方法,我们可以任取一个换c[i]个potions,花费d[i];或者是不取,我的做法就是枚举这些情况,得到剩余的s,再尽量优的获取小的a[i];
枚举+二分
#include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define ls i<<1 #define rs ls | 1 #define mid ((ll+rr)>>1) #define pii pair<int,int> #define MP make_pair typedef long long LL; const long long INF = 1e19+1LL; const double Pi = acos(-1.0); const int N = 5e5+10, maxn = 1e3+20, mod = 1e9+7, inf = 2e9; LL n,m,k,x,s,d[N],c[N],san[N]; struct ss{ LL a,b; }p[N],p1[N]; int check(LL T) { LL miT = INF; for(int i = 1; i <= k+1; ++i) { LL ret = s - d[i]; if(ret < 0) continue; if(ret < san[1]) { miT = min(miT,(n-c[i])*x); } else { if(san[m] < ret) { miT = min(miT,(n-c[i])*p1[m].a); } else { int pos = upper_bound(san+1,san+m+1,ret) - san - 1; miT = min(miT,(n-c[i])*p1[pos].a); } } } if(miT <= T) return 1; else return 0; } bool cmp(ss s1,ss s2) { return s1.b < s2.b; } int main() { scanf("%I64d%I64d%I64d%I64d%I64d",&n,&m,&k,&x,&s); for(int i = 1; i <= m; ++i) scanf("%I64d",&p[i].a); for(int i = 1; i <= m; ++i) scanf("%I64d",&p[i].b); sort(p+1,p+m+1,cmp); int cnt = 0; p1[++cnt] = p[1]; for(int i = 2; i <= m; ++i) { if(p[i].a >= p1[cnt].a) continue; p1[++cnt] = p[i]; } m = cnt; for(int i = 1; i <= m; ++i) san[i] = p1[i].b; for(int i = 1; i <= k; ++i) scanf("%I64d",&c[i]); for(int i = 1; i <= k; ++i) scanf("%I64d",&d[i]); LL l = 0, r = x*n; LL ans = x * n; while(l <= r) { LL md = (l+r)>>1; if(check(md)) { ans = md, r = md-1; } else l = md + 1; } cout<<ans<<endl; return 0; }
D
想要知道是否有个黑棋能不跳跃棋子一步走到白棋,白棋只有一个,我们将其8个方向第一碰到的黑棋挑出来判断黑棋行走方式是否可以到达白棋就可以了
#include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define ls i<<1 #define rs ls | 1 #define mid ((ll+rr)>>1) #define pii pair<int,int> #define MP make_pair typedef long long LL; const long long INF = 1e19+1LL; const double Pi = acos(-1.0); const int N = 1e6+10, maxn = 1e3+20, mod = 1e9+7, inf = 2e9; int n,x,y,d[N],can; char chs[N]; int ss[8][2] = {-1,0,0,-1,1,0,0,1,1,1,-1,-1,1,-1,-1,1}; struct ss{int x,y;} c[10],p[N];; int go(int j,int i) { int ok = 0; if(j == 0 && (p[i].x > c[j].x||c[j].x==inf))c[j] = p[i],ok=1; if(j == 1 && (p[i].y > c[j].y||c[j].y==inf))c[j] = p[i],ok=1; if(j == 2 && (p[i].x < c[j].x||c[j].x==inf))c[j] = p[i],ok=1; if(j == 3 && (p[i].y < c[j].y||c[j].y==inf))c[j] = p[i],ok=1; if(j == 4 && (p[i].x < c[j].x||c[j].x==inf))c[j] = p[i],ok=1; if(j == 5 && (p[i].x > c[j].x||c[j].x==inf))c[j] = p[i],ok=1; if(j == 6 && (p[i].x < c[j].x||c[j].x==inf))c[j] = p[i],ok=1; if(j == 7 && (p[i].x > c[j].x||c[j].x==inf))c[j] = p[i],ok=1; return ok; } int check(int j,int i) { can = 0; int xx = ss[j][0] + x; int yy = ss[j][1] + y; if((p[i].y-y)*(xx-x) != (p[i].x-x)*(yy-y)) return 0; if((p[i].y-y)*(yy-y) < 0 || (p[i].x-x)*(xx-x) < 0) return 0; if(j > 3 && chs[i] != 'R' ) can = 1; else if(j < 4 && chs[i] != 'B' ) can = 1; else can = 0; return 1; } int main() { char ch[2]; scanf("%d%d%d",&n,&x,&y); for(int i = 1; i <= n; ++i) { scanf("%s%d%d",ch,&p[i].x,&p[i].y); chs[i] = ch[0]; } for(int i = 0; i < 8; ++i) c[i].x = inf,c[i].y = inf; for(int i = 1; i <= n; ++i) { for(int j = 0; j < 8; ++j) { if(!check(j,i)||!go(j,i)) continue; if(can) d[j] = 1; else d[j] = 0; // cout<<j<<":"<<can<<endl; } } int ok = 0; for(int i = 0; i < 8; ++i) if(d[i]) ok = 1; if(ok) puts("YES");else puts("NO"); return 0; }
E
首先,对于颜色相同的且相连的点,我们将其看作一个点,那么新图就是黑白相连的树了
对于一个黑白间隔的图,最少的次数很容易算就是树直径除2,向下取整.
#include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define ls i<<1 #define rs ls | 1 #define mid ((ll+rr)>>1) #define pii pair<int,int> #define MP make_pair typedef long long LL; const long long INF = 1e18+1LL; const double Pi = acos(-1.0); const int N = 200000+10, maxn = 1e3+20, mod = 1e9+7, inf = 2e9; int n,a[N],fa[N],u[N],v[N],from,ans = -1; vector<int >G[N]; int finds(int x) {return x==fa[x]?x:fa[x]=finds(fa[x]);} void dfs(int u,int f,int dep) { if(dep > ans) { ans = dep; from = u; } for(int i = 0; i < G[u].size(); ++i) { int to = G[u][i]; if(to == f) continue; dfs(to,u,dep+1); } } int main() { scanf("%d",&n); for(int i = 1; i <= n; ++i) scanf("%d",&a[i]); for(int i = 1; i < n; ++i) scanf("%d%d",&u[i],&v[i]); for(int i = 1; i <= n; ++i) fa[i] = i; for(int i = 1; i < n; ++i) { int fx = finds(u[i]); int fy = finds(v[i]); if(a[u[i]] == a[v[i]]) { fa[fx] = fy; } } for(int i = 1; i < n; ++i) { int fx = finds(u[i]); int fy = finds(v[i]); if(a[fx] != a[fy]) { G[fx].push_back(fy); G[fy].push_back(fx); } } dfs(finds(1),-1,1); dfs(from,-1,1); printf("%d\n",ans/2); return 0; }
F
观察i,j得到
(a[i] and a[j]) + (a[i] or a[j]) = a[i] + a[j];
我们就这样轻松得到a数组了
如何判断?
对于数组a,取出二进制下60每个数的01情况来检查这个a数组是否满足题目条件 O(N*60)
#include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define ls i<<1 #define rs ls | 1 #define mid ((ll+rr)>>1) #define pii pair<int,int> #define MP make_pair typedef long long LL; const long long INF = 1e18+1LL; const double Pi = acos(-1.0); const int N = 200000+10, maxn = 1e3+20, mod = 1e9+7, inf = 2e9; LL a[N],n,b[N],c[N],num[N]; LL sum = 0; int main() { scanf("%I64d",&n); for(int i = 1; i <= n; ++i) scanf("%I64d",&b[i]),sum+=b[i]; for(int i = 1; i <= n; ++i) scanf("%I64d",&c[i]),sum+=c[i]; if(sum%(2LL*n)!=0) { puts("-1"); return 0; } sum = sum/(2*n); for(int i = 1; i <= n; ++i) { LL now = b[i]+c[i] - sum; if(now%n!=0) { puts("-1"); return 0; } a[i] = now/n; } for(int i = 1; i <= n; ++i) { LL tmp = a[i]; for(int j = 1; j <= 60; ++j) { num[j]+=tmp%2; tmp/=2; } } for(int i = 1; i <= n; ++i) { LL tmpb = 0, tmpc = 0; for(int j = 1; j <= 60; ++j) { if((a[i]&(1LL<<j-1))) tmpc += 1LL*n*(1LL<<j-1); else tmpc += 1LL*num[j]*(1LL<<j-1); if(a[i]&(1LL<<j-1)) tmpb += 1LL*num[j]*(1LL<<j-1); } //cout<<tmpb<<" "<<tmpc<<endl; if(tmpb != b[i] || tmpc != c[i]) { puts("-1");; return 0; } } for(int i = 1; i <= n; ++i) cout<<a[i]<<" "; return 0 ; }