2017-2018 ACM-ICPC, Central Europe Regional Contest (CERC 17)
A. Assignment Algorithm
按题意模拟即可。
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { }
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int N = 60, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei; int n, m, lft, rgt;
int empty[N];
char s[N][20];
int rk[10][2]; int main()
{
scanf("%d%d", &n, &m);
lft = n * 4; rgt = n * 4;
for(int i = 1; i <= n + 3; i ++){
empty[i] = 9;
scanf("%s", s[i] + 1);
for(int j = 1; j <= 11; j ++){
if(s[i][j] == '#'){
empty[i] --;
if(j <= 5) lft --;
else if(j >= 7) rgt --;
}
}
}
for(int ch = 0; ch < m; ch ++){
//printf("%d %d %d\n", ch, lft, rgt);
int tmpe = 0, o = 0, dis = 100;
if(ch == 13){
int go = 1;
}
if(empty[2]){
tmpe = empty[2];
o = 2;
}
if(empty[n / 2 + 3] > tmpe){
tmpe = empty[n / 2 + 3];
o = n / 2 + 3;
}
if(o == 0){
for(int i = 3; i <= n / 2 + 1; i ++){
if(empty[i] > tmpe){
tmpe = empty[i];
o = i;
dis = min(abs(i - n - 3), min(abs(i - 1), abs(i - n / 2 - 2)));
}
else if(empty[i] == tmpe){
int tmpdis = min(abs(i - n - 3), min(abs(i - 1), abs(i - n / 2 - 2)));
if(tmpdis < dis){
dis = tmpdis;
o = i;
}
}
}
for(int i = n / 2 + 4; i <= n + 2; i ++){
if(empty[i] > tmpe){
tmpe = empty[i];
o = i;
dis = min(abs(i - n - 3), min(abs(i - 1), abs(i - n / 2 - 2)));
}
else if(empty[i] == tmpe){
int tmpdis = min(abs(i - n - 3), min(abs(i - 1), abs(i - n / 2 - 2)));
if(tmpdis < dis){
dis = tmpdis;
o = i;
}
}
}
}
empty[o] --; rk[0][0] = 5, rk[0][1] = 7;
rk[1][0] = 3, rk[1][1] = 9;
rk[2][0] = 1, rk[2][1] = 11;
rk[3][0] = 6, rk[3][1] = 6;
rk[4][0] = 2, rk[4][1] = 10; for(int i = 0; i <= 4; i ++){
if(s[o][rk[i][0]] == '-' || s[o][rk[i][1]] == '-'){
if(i == 3){
s[o][6] = ch + 'a';
break;
}
if(s[o][rk[i][0]] == '-' && s[o][rk[i][1]] == '-'){
if(lft >= rgt) s[o][rk[i][0]] = ch + 'a', lft --;
else s[o][rk[i][1]] = ch + 'a', rgt --;
}
else if(s[o][rk[i][0]] == '-'){
s[o][rk[i][0]] = ch + 'a', lft --;
}
else {s[o][rk[i][1]] = ch + 'a', rgt --;}
break;
}
}
} for(int i = 1; i <= n + 3; i ++){
printf("%s\n", s[i] + 1);
}
return 0;
} /*
2 17
...........
---.#--.---
...........
---.---.---
........... 6 26
...........
---.---.###
#-#.---.---
---.###.---
...........
---.###.---
#--.#-#.--#
#--.--#.#-#
........... 0 17 12
1 16 12
2 15 12
3 15 11
4 15 10
5 14 10
6 13 10
7 12 10
8 12 9
9 12 9
10 11 9
11 10 9
12 10 8
13 9 8
14 8 8
15 8 7
16 8 6
17 7 6
18 7 5
19 6 5
20 5 5
21 4 5
22 4 4
23 4 3
24 4 2
25 4 2
...........
gke.aic.###
#-#.mzo.r-v
t-n.###.p-x
...........
fjb.###.dlh
#-s.#-#.w-#
#-u.qy#.#-#
........... */ /*
【trick&&吐槽】 【题意】 【分析】 【时间复杂度&&优化】 */
B. Buffalo Barricades
首先通过扫描线求出最终的图中每个点属于哪个区域,以及包含每个区域的最小区域。
然后倒着处理每个询问,依次删掉每个栅栏,也就是将区域的点数合并,并查集维护。
时间复杂度$O((n+m)\log(n+m))$。
#include<cstdio>
#include<algorithm>
#include<set>
using namespace std;
typedef pair<int,int>P;
const int N=600010;
int n,m,ce,i,x,y,z,v[N],f[N],g[N],ans[N];set<P>T;
struct E{int x,y,t;E(){}E(int _x,int _y,int _t){x=_x,y=_y,t=_t;}}e[N];
inline bool cmp(const E&a,const E&b){
if(a.y!=b.y)return a.y>b.y;
return a.x<b.x;
}
inline int F(int x){return f[x]==x?x:f[x]=F(f[x]);}
inline void merge(int x,int y){
x=F(x),y=F(y);
if(x==y)return;
f[x]=y,v[y]+=v[x];
}
int main(){
scanf("%d",&n);
for(i=1;i<=n;i++){
scanf("%d%d",&x,&y);
x<<=1,y<<=1;
e[++ce]=E(x,y,0);
}
scanf("%d",&m);
for(i=1;i<=m;i++){
scanf("%d%d",&x,&y);
x<<=1,y<<=1;
x++,y++;
e[++ce]=E(x,y,i);
f[i]=i;
}
sort(e+1,e+ce+1,cmp);
for(i=1;i<=ce;i++){
x=e[i].x,z=e[i].t;
if(z){
T.insert(P(x,z));
set<P>::iterator it=T.find(P(x,z)),k=it;
k++;
if(k!=T.end())g[z]=k->second;
while(1){
k=T.find(P(x,z));
if(k==T.begin())break;
k--;
if(k->second<z)break;
T.erase(k);
}
}else{
set<P>::iterator it=T.lower_bound(P(x,0));
if(it!=T.end())v[it->second]++;
}
}
for(i=m;i;i--){
ans[i]=v[F(i)];
if(g[i])merge(i,g[i]);
}
for(i=1;i<=m;i++)printf("%d\n",ans[i]);
}
C. Cumulative Code
留坑。
D. Donut Drone
LCT维护环套树,在根与根的父亲处断开。
对于link操作,若成环则无视。
对于cut操作,删边之后再将环边link即可。
对于查询操作,首先求出与环末端点的LCA,这就是进入环的点,剩下的部分模环长后分两段走即可。
时间复杂度$O(n\log n)$。
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=2010,M=N*N;
int n,m,a[M],f[M],son[M][2],size[M];
int v[N][N],id[N][N],tot,loc[M][2],O;
int i,j,k,x,y,z;char op[100];
inline bool isroot(int x){return !f[x]||son[f[x]][0]!=x&&son[f[x]][1]!=x;}
inline void up(int x){size[x]=size[son[x][0]]+size[son[x][1]]+1;}
inline void rotate(int x){
int y=f[x],w=son[y][1]==x;
son[y][w]=son[x][w^1];
if(son[x][w^1])f[son[x][w^1]]=y;
if(f[y]){
int z=f[y];
if(son[z][0]==y)son[z][0]=x;
else if(son[z][1]==y)son[z][1]=x;
}
f[x]=f[y];f[y]=x;son[x][w^1]=y;up(y);
}
inline void splay(int x){
while(!isroot(x)){
int y=f[x];
if(!isroot(y)){if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);else rotate(y);}
rotate(x);
}
up(x);
}
inline int access(int x){
int y=0;
for(;x;y=x,x=f[x])splay(x),son[x][1]=y,up(x);
return y;
}
inline int lca(int x,int y){
access(x);
return access(y);
}
inline int root(int x){
access(x);
splay(x);
while(son[x][0])x=son[x][0];
splay(x);
return x;
}
inline void link(int x,int y){
if(root(x)!=root(y))splay(x),f[x]=y,access(x);
}
inline void cut(int x,int y){
int u=root(x);
if(u==x)return;
access(x);
splay(x);
f[son[x][0]]=0;
son[x][0]=0;
up(x);
link(u,a[u]);
}
inline int dis(int x){
access(x);
splay(x);
return size[son[x][0]];
}
inline int goup(int x,int k){
k=dis(x)-k+1;
access(x);
splay(x);
while(1){
int t=size[son[x][0]]+1;
if(k==t)return x;
if(k<t)x=son[x][0];else k-=t,x=son[x][1];
}
}
inline int moveup(int x,int k){
x=goup(x,k);
splay(x);
return x;
}
inline int simulate(int x,int k){
int u=root(x),y=a[u],z=lca(x,y);
int A=dis(x),B=dis(y),C=dis(z);
if(A>C){
int t=min(A-C,k);
k-=t;
x=moveup(x,t);
}
k%=B+1;
if(!k)return x;
int t=min(dis(x),k);
k-=t;
x=moveup(x,t);
if(!k)return x;
x=y;
k--;
if(!k)return x;
return moveup(x,k);
}
inline int getnxt(int o){
int x=loc[o][0],y=loc[o][1];
y++;
y%=m;
int mx=-1,w=0;
for(int i=x-1;i<=x+1;i++){
int nx=(i%n+n)%n;
if(v[nx][y]>mx){
mx=v[nx][y];
w=id[nx][y];
}
}
return w;
}
inline void check(int x,int y){
x%=n,y%=m;
x+=n,y+=m;
x%=n,y%=m;
int o=id[x][y];
int now=getnxt(o);
if(a[o]!=now){
cut(o,a[o]);
a[o]=now;
link(o,a[o]);
}
}
int main(){
scanf("%d%d",&n,&m);
for(i=0;i<n;i++)for(j=0;j<m;j++){
scanf("%d",&v[i][j]);
id[i][j]=++tot;
loc[tot][0]=i;
loc[tot][1]=j;
}
for(i=1;i<=tot;i++)size[i]=1;
for(i=1;i<=tot;i++){
a[i]=getnxt(i);
link(i,a[i]);
}
O=id[0][0];
int _;
scanf("%d",&_);
while(_--){
scanf("%s",op);
if(op[0]=='c'){
scanf("%d%d%d",&x,&y,&z);
x--,y--;
v[x][y]=z;
check(x-1,y-1);
check(x,y-1);
check(x+1,y-1);
}else{
scanf("%d",&k);
O=simulate(O,k);
printf("%d %d\n",loc[O][0]+1,loc[O][1]+1);
}
}
}
/*
3 4
10 20 30 40
50 60 70 80
90 93 95 99
3
move 4
change 2 1 100
move 4
*/
E. Embedding Enumeration
留坑。
F. Faulty Factorial
显然要修改的数与$n$相差不超过$P$,枚举每个数分类讨论即可。
#include<cstdio>
#include<cstdlib>
using namespace std;
typedef long long ll;
const int N=10000010;
ll n;
int P,R,i;
int s[N],inv[N];
inline ll po(ll a,ll b,ll P){
ll t=1;
for(;b;b>>=1,a=a*a%P)if(b&1)t=t*a%P;
return t;
}
struct Num{
ll a,b;
Num(){a=1,b=0;}
Num(ll _a,ll _b){a=_a,b=_b;}
Num operator*(Num x){return Num(a*x.a%P,b+x.b);}
Num operator/(Num x){return Num(a*inv[x.a]%P,b-x.b);}
}res;
Num cal(ll n){
return n?Num(s[n%P]*po(s[P],n/P,P)%P,n/P)*cal(n/P):Num(1,0);
}
inline Num ask(ll n){
ll b=0;
while(n%P==0)n/=P,b++;
return Num(n%P,b);
}
void ok(ll a,ll b){
printf("%lld %lld",a,b);
exit(0);
}
int main(){
scanf("%lld%d%d",&n,&P,&R);
for(i=s[0]=1;i<P;i++)s[i]=1LL*s[i-1]*i%P;
s[P]=s[P-1];
for(inv[0]=inv[1]=1,i=2;i<P;i++)inv[i]=1LL*(P-inv[P%i])*(P/i)%P;
res=cal(n);
ll W=1LL*R*inv[res.a]%P;
for(ll x=n;x>1&&x>n-P-10;x--){
ll A=x,B=0;
while(A%P==0)A/=P,B++;
if(res.b>B){
if(R)continue;
ok(x,1);
}else{
if(R){
ll y=A%P*W%P;
if(y<x)ok(x,y);
}else{
if(P<x)ok(x,P);
}
}
}
puts("-1 -1");
}
G. Gambling Guide
设$e_x$表示$x$到$n$的最优期望次数,则$e_n=0,e_x=\frac{\sum\min(e_x,e_y)}{deg_x}+1$。
每次用堆取出$e_x$最小的$x$,更新周围一圈点即可。
时间复杂度$O(m\log m)$。
#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
typedef pair<double,int>P;
const int N=300010;
const double inf=1e100;
int n,m,i,x,y,g[N],v[N<<1],nxt[N<<1],ed;
double f[N],s[N];
int d[N],c[N];
bool vis[N];
priority_queue<P,vector<P>,greater<P> >q;
inline void add(int x,int y){
v[++ed]=y;nxt[ed]=g[x];g[x]=ed;
d[x]++;
}
inline void ext(int x){
double now=(s[x]+d[x])/c[x];
if(now<f[x]){
f[x]=now;
q.push(P(now,x));
}
}
inline void up(int x,double y){
vis[x]=1;
for(int i=g[x];i;i=nxt[i]){
int u=v[i];
if(vis[u])continue;
c[u]++;
s[u]+=y;
ext(u);
}
}
int main(){
scanf("%d%d",&n,&m);
while(m--){
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
for(i=1;i<n;i++)f[i]=inf;
q.push(P(0,n));
while(!q.empty()){
P t=q.top();q.pop();
if(vis[t.second])continue;
up(t.second,t.first);
}
printf("%.10f",f[1]);
}
H. Hidden Hierarchy
按题意模拟即可。
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int L = 1e5 + 10, N = 0, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
int T;
char s[L];
map<string, set<string> >mop;
map<string, int>v;
void dfs1(string x)
{
for(auto y : mop[x])
{
dfs1(y);
v[x] += v[y];
}
}
void dfs2(string x)
{
if(!mop[x].size())
{
printf("%c %s %d\n", ' ', x.c_str(), v[x]);
return;
}
bool flag = 0;
for(auto y : mop[x])
{
if(v[y] >= T)flag = 1;
}
if(!flag)
{
printf("%c %s %d\n", '+', x.c_str(), v[x]);
return;
}
else
{
printf("%c %s %d\n", '-', x.c_str(), v[x]);
for(auto y : mop[x])
{
dfs2(y);
}
}
}
int main()
{
int n;
while(~scanf("%d", &n))
{
mop.clear();v.clear();
for(int i = 1; i <= n; ++i)
{
int val;
scanf("%s%d", s, &val);
string fa = "#";
for(int i = 0; s[i]; ++i)if(s[i] == '/')
{
char tmp = s[i + 1];
s[i + 1] = 0;
mop[fa].insert(s);
fa = s;
s[i + 1] = tmp;
}
v[fa] += val;
}
string rt = "/";
dfs1(rt);
//
//printf("%d\n", v[rt]);
//
scanf("%d", &T);
dfs2(rt);
}
return 0;
}
/*
【trick&&吐槽】
2
/a/a/a 100
/b.txt 99
200 【题意】 【分析】 【时间复杂度&&优化】 */
I. Intrinsic Interval
若一个区间$[l,r]$满足$max-min=r-l$,则值域连续。
也就是$max-min-r+l=0$,注意到$max-min-r+l\geq 0$恒成立,故为了在合法的情况下区间长度最短,应该满足$v=(max-min-r+l)n+r-l$最小,区间长度即为$v\bmod n$。
利用单调栈求出每个数作为最值的范围,对应$v$的矩形加。
从左往右考虑每个$l$,用线段树维护每个$r$的$v$,对于一个询问,答案即为区间历史最小值,线段树维护即可。
时间复杂度$O((n+m)\log n)$。
#include<cstdio>
#include<algorithm>
#define lc x<<1
#define rc x<<1|1
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const int N=100010,M=262150,E=500010;
const ll inf=1LL<<60;
int n,Q,i,j,a[N],t,q[N],l[N],r[N];
int ga[N],gd[N],gq[N],ed,vl[E],vr[E],nxt[E];ll w[E];
P ans[N];
ll m[M],hm[M],d[M],hd[M];
ll fin;
int pos;
inline void Min(ll&a,ll b){a>b?(a=b):0;}
inline void hdoa(int x,ll v){
Min(hm[x],m[x]+v);
Min(hd[x],d[x]+v);
}
inline void doa(int x,ll v){
Min(hm[x],m[x]+=v);
Min(hd[x],d[x]+=v);
}
inline void pb(int x){
if(hd[x])hdoa(lc,hd[x]),hdoa(rc,hd[x]),hd[x]=0;
if(d[x])doa(lc,d[x]),doa(rc,d[x]),d[x]=0;
}
inline void up(int x){
m[x]=min(m[lc],m[rc]);
Min(hm[x],min(hm[lc],hm[rc]));
}
void build(int x,int a,int b){
if(a==b){
hm[x]=m[x]=-1LL*a*(n-1);
return;
}
int mid=(a+b)>>1;
build(x<<1,a,mid);
build(x<<1|1,mid+1,b);
up(x);
}
void dfs(int x,int a,int b){
if(a==b){
hm[x]=m[x];
return;
}
pb(x);
int mid=(a+b)>>1;
dfs(x<<1,a,mid);
dfs(x<<1|1,mid+1,b);
m[x]=min(m[lc],m[rc]);
hm[x]=min(hm[lc],hm[rc]);
}
void add(int x,int f,int t,int qf,int qt,ll v){
if(qf<=f&&t<=qt){doa(x,v);return;}
pb(x);
int mid=(f+t)>>1;
if(qf<=mid)add(lc,f,mid,qf,qt,v);
if(qt>mid)add(rc,mid+1,t,qf,qt,v);
up(x);
} inline void addedge(int&x,int l,int r,ll z){
vl[++ed]=l;
vr[ed]=r;
w[ed]=z;
nxt[ed]=x;
x=ed;
}
inline void ext(int xl,int xr,int yl,int yr,ll w){
//printf("%d %d %d %d %lld\n",xl,xr,yl,yr,w);
if(w>=0){
addedge(ga[xl],yl,yr,w);
addedge(gd[xr+1],yl,yr,-w);
}else{
addedge(gd[xl],yl,yr,w);
addedge(ga[xr+1],yl,yr,-w);
}
} void ask(int x,int a,int b,int c,int d){
if(c<=a&&b<=d){
Min(fin,hm[x]);
return;
}
pb(x);
int mid=(a+b)>>1;
if(c<=mid)ask(x<<1,a,mid,c,d);
if(d>mid)ask(x<<1|1,mid+1,b,c,d);
}
void getpos(int x,int a,int b,int c,int d){
if(pos)return;
if(hm[x]>fin)return;
if(a==b){
pos=a;
return;
}
pb(x);
int mid=(a+b)>>1;
if(c<=mid)getpos(x<<1,a,mid,c,d);
if(d>mid)getpos(x<<1|1,mid+1,b,c,d);
} inline P query(int l,int r){
fin=inf;
ask(1,1,n,r,n);
//printf("! %d %d %lld\n",l,r,fin);
pos=0;
getpos(1,1,n,r,n);
return P(pos-fin%n,pos);
} int main(){
//(ma-mi-r+l)*n+r-l
//ma*n-mi*n-r*(n-1)+l*(n-1)
scanf("%d",&n);
for(i=1;i<=n;i++)scanf("%d",&a[i]);
scanf("%d",&Q);
for(i=1;i<=Q;i++){
int x,y;
scanf("%d%d",&x,&y);
addedge(gq[x],i,y,0);
} for(q[t=0]=0,i=1;i<=n;i++){
while(t&&a[i]>a[q[t]])t--;
l[i]=q[t]+1;
q[++t]=i;
}
for(q[t=0]=n+1,i=n;i;i--){
while(t&&a[i]>a[q[t]])t--;
r[i]=q[t]-1;
q[++t]=i;
}
for(i=1;i<=n;i++)ext(l[i],i,i,r[i],1LL*a[i]*n); for(q[t=0]=0,i=1;i<=n;i++){
while(t&&a[i]<a[q[t]])t--;
l[i]=q[t]+1;
q[++t]=i;
}
for(q[t=0]=n+1,i=n;i;i--){
while(t&&a[i]<a[q[t]])t--;
r[i]=q[t]-1;
q[++t]=i;
}
for(i=1;i<=n;i++)ext(l[i],i,i,r[i],-1LL*a[i]*n); build(1,1,n);
for(i=1;i<=n;i++){
add(1,1,n,1,n,n-1);
for(j=ga[i];j;j=nxt[j]){
add(1,1,n,vl[j],vr[j],w[j]);
}
for(j=gd[i];j;j=nxt[j]){
add(1,1,n,vl[j],vr[j],w[j]);
}
if(i==1)dfs(1,1,n);
for(j=gq[i];j;j=nxt[j]){
ans[vl[j]]=query(i,vr[j]);
}
} for(i=1;i<=Q;i++)printf("%d %d\n",ans[i].first,ans[i].second);
}
/*
7
3 1 7 5 6 4 2
3
3 6
7 7
1 3 7
3 1 7 5 6 4 2
3
3 6
7 7
1 3
1 1 1 2 21
2 2 2 2 7
1 3 3 7 49
4 4 4 4 35
4 5 5 7 42
6 6 6 7 28
7 7 7 7 14
1 1 1 1 -21
1 2 2 7 -7
3 3 3 3 -49
3 4 4 5 -35
5 5 5 5 -42
3 6 6 6 -28
3 7 7 7 -14
! 1 3 -12
! 3 6 -30
! 7 7 -36
8 6
8 7
8 3 */
J. Justified Jungle
枚举每个$k$,那么剩下每个子树大小均为$\frac{n}{k+1}$,因此$k+1$一定是$n$的因子,若此时还满足子树大小为它的倍数的点数够$k+1$个,则可行。
#include<cstdio>
const int N=1000010;
int n,i,x,y,g[N],v[N<<1],nxt[N<<1],ed;
int size[N];
int cnt[N];
inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
void dfs(int x,int y){
size[x]=1;
for(int i=g[x];i;i=nxt[i])if(v[i]!=y)dfs(v[i],x),size[x]+=size[v[i]];
cnt[size[x]]++;
}
inline bool check(int x){
x++;
if(n%x)return 0;
int w=n/x,t=0;
for(int i=w;i<=n;i+=w)t+=cnt[i];
return t==x;
}
int main(){
scanf("%d",&n);
for(i=1;i<n;i++)scanf("%d%d",&x,&y),add(x,y),add(y,x);
dfs(1,0);
for(i=1;i<n;i++)if(check(i))printf("%d ",i);
}
K. Kitchen Knobs
因为$7$的因子只有$1$和$7$,因此最大值要么有$1$种,要么有$7$种,$7$种的显然无论怎么操作都是最优的,可以直接删掉。
问题转化为:给定$n$个数$a_1,a_2,...,a_n$,每次可以选择一个区间加上一个数,用最少的操作次数让所有数模$7$都为$0$。
将$a$差分,区间加操作也差分,则问题转化为:每次可以选择两个数,一个加上$k$,另一个减去$k$,用最少的操作次数让所有数模$7$都为$0$。
首先无视$0$,那么一定是先$1,6$配对、$2,5$配对、$3,4$配对,如此处理后最多还有$3$种数字$A,B,C$,问题转化为将这些数分成最多的组数,使得每组和都为$0$,记录$3$个数每个的个数然后DP即可。
#include<cstdio>
#include<string>
#include<algorithm>
#include<iostream>
using namespace std;
const int N=505,inf=10000;
int _,n,a[N],A,B,C,i,j,k,x,y,z,cnt[7],ans,m,e[N][4];short f[N][N][N],t;
inline void up(short&a,short b){a>b?(a=b):0;}
int ask(){
static char s[20];
scanf("%s",s);
string best="";
for(int i=0;i<7;i++)best.push_back(s[i]);
int mask=1;
int sum=0;
for(int i=1;i<7;i++){
string now="";
for(int j=0;j<7;j++){
now.push_back(s[(i+j)%7]);
}
if(now==best){
mask|=1<<i;
sum+=i;
}else if(now>best){
mask=1<<i;
sum=i;
best=now;
}
}
if(mask!=(mask&(-mask)))return -1;
return sum;
}
int main(){
scanf("%d",&_);
while(_--){
int x=ask();
if(x<0)continue;
a[++n]=x;
}
if(!n)return puts("0"),0;
for(i=n+1;i;i--)a[i]-=a[i-1];
for(i=1;i<=n+1;i++)a[i]=((a[i]%7+7)%7);
for(i=1;i<=n+1;i++)cnt[a[i]]++;
while(cnt[1]&&cnt[6])cnt[1]--,cnt[6]--,ans++;
A=cnt[1]?cnt[1]:cnt[6];
x=cnt[1]?1:6;
while(cnt[2]&&cnt[5])cnt[2]--,cnt[5]--,ans++;
B=cnt[2]?cnt[2]:cnt[5];
y=cnt[2]?2:5;
while(cnt[3]&&cnt[4])cnt[3]--,cnt[4]--,ans++;
C=cnt[3]?cnt[3]:cnt[4];
z=cnt[3]?3:4;
for(i=0;i<=7;i++)for(j=0;j<=7;j++)for(k=0;k<=7;k++)if(i+j+k&&(i*x+j*y+k*z)%7==0){
e[m][0]=i;
e[m][1]=j;
e[m][2]=k;
e[m++][3]=i+j+k-1;
}
for(i=0;i<=A;i++)for(j=0;j<=B;j++)for(k=0;k<=C;k++)if(i+j+k){
t=inf;
for(x=0;x<m;x++)if(i>=e[x][0]&&j>=e[x][1]&&k>=e[x][2])up(t,f[i-e[x][0]][j-e[x][1]][k-e[x][2]]+e[x][3]);
f[i][j][k]=t;
}
printf("%d",ans+f[A][B][C]);
}
L. Lunar Landscape
利用二维前缀和标记出所有被覆盖的位置即可。
#include<cstdio>
const int K=2005,N=4100;
int n,x,y,d,i,j,k,a[N][N],b[N][N],f[N][N],ans;char op[9];
int main(){
scanf("%d",&n);
while(n--){
scanf("%s%d%d%d",op,&x,&y,&d);
x+=K,y+=K;
if(op[0]=='A'){
x-=d/2,y-=d/2;
a[x][y]++;
a[x+d][y]--;
a[x][y+d]--;
a[x+d][y+d]++;
}else{
d/=2;
b[x][y-d]++;
b[x-d][y]--;
b[x+d][y]--;
b[x][y+d]++;
}
}
for(i=1;i<N;i++)for(j=1;j<N;j++){
a[i][j]+=a[i-1][j]+a[i][j-1]-a[i-1][j-1];
if(a[i][j])f[i][j]|=15;
}
for(j=1;j<N;j++)for(i=1;i<N;i++){
b[i][j]+=b[i-1][j-1]+b[i+1][j-1];
if(j>=2)b[i][j]-=b[i][j-2];
if(b[i][j]){
f[i][j]|=12;
f[i][j+1]|=9;
f[i-1][j]|=6;
f[i-1][j+1]|=3;
}
}
for(i=1;i<N;i++)for(j=1;j<N;j++)for(k=0;k<4;k++)if(f[i][j]>>k&1)ans++;
printf("%.2f",0.25*ans);
}
2017-2018 ACM-ICPC, Central Europe Regional Contest (CERC 17)的更多相关文章
- ACM ICPC Central Europe Regional Contest 2013 Jagiellonian University Kraków
ACM ICPC Central Europe Regional Contest 2013 Jagiellonian University Kraków Problem A: Rubik’s Rect ...
- Central Europe Regional Contest 2012 Problem H: Darts
http://acm.hunnu.edu.cn/online/problem_pdf/CERC2012/H.pdf HUNNU11377 题意:飞镖环有十个环,没个环从外到里对应一个得分1~10,每个 ...
- Central Europe Regional Contest 2012 Problem I: The Dragon and the Knights
一个简单的题: 感觉像计算几何,其实并用不到什么计算几何的知识: 方法: 首先对每条边判断一下,看他们能够把平面分成多少份: 然后用边来对点划分集合,首先初始化为一个集合: 最后如果点的集合等于平面的 ...
- Central Europe Regional Contest 2012 Problem c: Chemist’s vows
字符串处理的题目: 学习了一下string类的一些用法: 这个代码花的时间很长,其实可以更加优化: 代码: #include<iostream> #include<string> ...
- Central Europe Regional Contest 2012 Problem J: Conservation
题目不难,感觉像是一个拓扑排序,要用双端队列来维护: 要注意细节,不然WA到死 = =! #include<cstdio> #include<cstring> #includ ...
- ICPC Central Russia Regional Contest (CRRC 19)题解
题目连接:https://codeforces.com/gym/102780 寒假第二次训练赛,(某菜依旧是4个小时后咕咕咕),战况还行,个人表现极差(高级演员) A:Green tea 暴力枚举即可 ...
- 2020.5.16-ICPC Central Europe Regional Contest 2019
A. ABB #include <bits/stdc++.h> using namespace std; #define PB push_back #define ZERO (1e-10) ...
- 2018 ICPC Pacific Northwest Regional Contest I-Inversions 题解
题目链接: 2018 ICPC Pacific Northwest Regional Contest - I-Inversions 题意 给出一个长度为\(n\)的序列,其中的数字介于0-k之间,为0 ...
- 2019-2020 ICPC, Asia Jakarta Regional Contest (Online Mirror, ICPC Rules, Teams Preferred)
2019-2020 ICPC, Asia Jakarta Regional Contest (Online Mirror, ICPC Rules, Teams Preferred) easy: ACE ...
随机推荐
- c++三种继承方式public,protect,private
C++中的三种继承public,protected,private 三种访问权限 public:可以被任意实体访问 protected:只允许子类及本类的成员函数访问 private:只允许本类的成员 ...
- linux log4j乱码问号的解决
原因: linux本地设置的文件编码格式不是UTF-8 解决办法: 运行locale命令看一下结果: 把LC_CTYPE修改为“zh_CN.UTF-8”: cd ~/ vi .bashrc 添加: L ...
- EXCEL(1)级联下拉框
EXCEL级联下拉框 http://jingyan.baidu.com/article/3c343ff756e0cf0d377963f9.html 在输入一些多级项目时,如果输入前一级内容后,能够自动 ...
- Python:正则表达式详解
正则表达式是一个很强大的字符串处理工具,几乎任何关于字符串的操作都可以使用正则表达式来完成,作为一个爬虫工作者,每天和字符串打交道,正则表达式更是不可或缺的技能,正则表达式的在不同的语言中使用方式可能 ...
- es6常用的
常用: let关键字: 1. 作用: * 与var类似, 用于声明一个变量2. 特点: * 在块作用域内有效 * 不能重复声明 * 不会预处理, 不存在提升3. 应用: * 循环遍历加监听 * 使用l ...
- MySQL实战45讲学习笔记:事务隔离级别(第三讲)
一.隔离性与隔离级别 1.事务的特性 原子性 一致性 隔离性 持久性 2.不同事务隔离级别的区别 读未提交:别人改数据的事务尚未提交,我在我的事务中也能读到.读已提交:别人改数据的事务已经提交,我在我 ...
- Java IO流操作汇总: inputStream 和 outputStream【转】
我们在进行Android java 开发的时候,经常会遇到各种IO流操作.IO流操作一般分为两类:字符流和字节流.以“Reader”结尾都是字符流,操作的都是字符型的数据:以“Stream”结尾的都是 ...
- 🍓rem单位在Chrome中字体大小异常 🍓
这是一个很少出现,而一旦出现就让人头疼难当的bug.....网上资料比较少. 解决:https://oss.so/article/87 即为html标签设置-webkit-text-size-adju ...
- python的request包
1,request包基本用法 import requests a=requests.get("http://www.baidu.com")print a.text #以文本形式打印 ...
- 设计模式十: 生成器模式(Builder Pattern)
简介 生成器模式属于创建型模式的一种, 又叫建造者模式. 生成器模式涉及4个关键角色:产品(Product),抽象生成器(builder),具体生成器(ConcreteBuilder),指挥者(Dir ...