将方格按照蛇形抽成序列:
序列中的连续一段格子必然形成连通块。对这个序列进行划分即可。
#include
#include
#include
#include
#define ll long long
using namespace std;
template <class T>
inline void rd(T &x) {
x=0; char c=getchar(); int f=1;
while(!isdigit(c)) { if(c=='-') f=-1; c=getchar(); }
while(isdigit(c)) x=x*10-'0'+c,c=getchar(); x*=f;
}
const int N=110;
int n,m;
char str[N];
int seq[N*N],col[N*N];
char mp[100];
int main() {
for(int i=0;i<26;++i) mp[i+1]='a'+i;
for(int i=0;i<26;++i) mp[i+27]='A'+i;
for(int i=0;i<10;++i) mp[i+53]='0'+i;
int T; rd(T);
while(T--) {
int k;
rd(n),rd(m),rd(k);
int tot=0,pos=0;
for(int i=1;i<=n;++i) {
scanf("%s",str+1);
if(i&1) {
for(int j=1;j<=m;++j) {
seq[++pos]=str[j]=='R';
tot+=str[j]=='R';
}
}
else {
for(int j=m;j>=1;--j) {
seq[++pos]=str[j]=='R';
tot+=str[j]=='R';
}
}
}
int lst=1,lim;
for(lim=tot/k,tot-=lim;;--k,lim=tot/k,tot-=lim) {
for(;lim;lim-=seq[lst],col[lst]=k,lst++);
if(k==1) break;
}
for(;lst<=pos;col[lst]=k,lst++);
for(int i=1;i<=n;++i,puts("")) {
if(i&1) {
for(int j=1;j<=m;++j)
putchar(mp[col[(i-1)*m+j]]);
}
else {
for(int j=1;j<=m;++j)
putchar(mp[col[(i-1)*m+(m-j+1)]]);
}
}
}
return 0;
}
k k k必须是 ∑ a i \sum a_i ∑ai的因子。
如果确定了 k k k,策略必然是按照在序列中的位置从左到右把巧克力排开,每连续的 k k k个放到一起。放的位置是这些盒子的位置的中位数。
显然当 k k k不是质数的时候一定不优秀。
枚举 ∑ a i \sum a_i ∑ai的每个质因子算答案取最优即可。
#include
#include
#include
#include
#include
#define PB push_back
#define ll long long
using namespace std;
template <class T>
inline void rd(T &x) {
x=0; char c=getchar(); int f=1;
while(!isdigit(c)) { if(c=='-') f=-1; c=getchar(); }
while(isdigit(c)) x=x*10-'0'+c,c=getchar(); x*=f;
}
inline int Abs(int x) { return x>0?x:-x; }
const int N=1e6+10;
ll m,a[N],b[N];
int n;
ll sol(int l,int r,ll pos) {
pos=(pos+1)/2; ll cur=0;
int mid;
for(int i=l;i<=r;++i) {
cur+=b[i];
if(cur>=pos) { mid=i; break; }
}
ll ans=0;
for(int i=l;i<=r;++i) ans+=Abs(i-mid)*b[i];
return ans;
}
ll work(ll pr) {
ll ans=0;
int lst=1; ll cnt=0;
for(int i=1;i<=n;++i) {
if(cnt+a[i]>=pr) {
b[i]=pr-cnt;
ans+=sol(lst,i,pr);
b[i]=(a[i]-(pr-cnt))%pr;
cnt=b[i];
lst=i;
}
else cnt+=a[i],b[i]=a[i];
}
return ans;
}
int main() {
rd(n);
for(int i=1;i<=n;++i) rd(a[i]),m+=a[i];
if(m==1) {
printf("-1");
return 0;
}
ll ans=1e18;
for(int i=2;i*(ll)i<=m;++i) if(m%i==0) {
while(m%i==0) m/=i;
ans=min(ans,work(i));
}
if(m>1) ans=min(ans,work(m));
printf("%lld",ans);
return 0;
}
首先随便选两个点 p 1 , p 2 p_1,p_2 p1,p2,然后对剩下的点问一遍 2 2 2,区分出它们在 p 1 p 2 → \overrightarrow{p_1p_2} p1p2划分出的哪个半平面内。
对于每个半平面内:问出所有点与 p 1 , p 2 p_1,p_2 p1,p2组成的三角形的面积,假设这其中面积最大的那个点是 q q q,再问出每个点是在 p 1 q → \overrightarrow{p_1q} p1q的哪个方向,从 p 1 p_1 p1到 q q q之间的那些点按照与 p 1 , p 2 p_1,p_2 p1,p2组成的三角形面积从小到大排列, q q q到 p 2 p_2 p2之间的点从大到小排列。
#include
#include
#include
#include
#include
#define PB push_back
#define ll long long
using namespace std;
template <class T>
inline void rd(T &x) {
x=0; char c=getchar(); int f=1;
while(!isdigit(c)) { if(c=='-') f=-1; c=getchar(); }
while(isdigit(c)) x=x*10-'0'+c,c=getchar(); x*=f;
}
int n,ans;
vector<int> v1,v2;
vector<int> s1,s2;
ll ar[1010];
bool cmp(int x,int y) { return ar[x]<ar[y]; }
void sol(int l,int r,vector<int> &v) {
if(v.size()==0) return;
s1.clear(),s2.clear();
int p=0;
for(int i=1;i<v.size();++i) if(ar[v[i]]>ar[v[p]]) p=i;
int q=v[p];
for(int i=0;i<v.size();++i) if(i!=p) {
printf("2 1 %d %d\n",q,v[i]);
fflush(stdout);
rd(ans);
if(ans==1) s2.PB(v[i]);
else s1.PB(v[i]);
}
sort(s2.begin(),s2.end(),cmp);
sort(s1.begin(),s1.end(),cmp);
v.clear();
for(int i=0;i<s1.size();++i) v.PB(s1[i]);
v.PB(q);
for(int i=(int)s2.size()-1;i>=0;--i) v.PB(s2[i]);
}
int main() {
rd(n);
for(int i=3;i<=n;++i) {
printf("2 1 2 %d\n",i);
fflush(stdout);
rd(ans);
if(ans==1) v2.PB(i);
else v1.PB(i);
printf("1 1 2 %d\n",i);
fflush(stdout);
rd(ar[i]);
}
sol(1,2,v1);
sol(2,1,v2);
printf("0 ");
printf("1 ");
for(int i=0;i<v1.size();++i) printf("%d ",v1[i]);
printf("2 ");
for(int i=0;i<v2.size();++i) printf("%d ",v2[i]);
return 0;
}
对询问分块,复杂度 O ( n log n + n n ) O(n\log n + n\sqrt n) O(nlogn+nn)。
#include
#include
#include
#include
#include
#define PB push_back
#define ll long long
using namespace std;
template <class T>
inline void rd(T &x) {
x=0; char c=getchar(); int f=1;
while(!isdigit(c)) { if(c=='-') f=-1; c=getchar(); }
while(isdigit(c)) x=x*10-'0'+c,c=getchar(); x*=f;
}
const int N=150010,mod=998244353;
int Pow(int x,int y) {
int res=1;
while(y) {
if(y&1) res=res*(ll)x%mod;
x=x*(ll)x%mod,y>>=1;
}
return res;
}
int head[N],ecnt;
int sz[N],fa[N];
struct ed { int to,next; }e[N<<1];
void ad(int x,int y) {
e[++ecnt]=(ed){y,head[x]}; head[x]=ecnt;
e[++ecnt]=(ed){x,head[y]}; head[y]=ecnt;
}
namespace __ {
int *U[N],*D[N];
int dep[N],son[N],top[N];
int dis[N];
int p[N][19];
void dfs1(int u,int last) {
fa[u]=p[u][0]=last,dis[u]=dis[last]+1;
sz[u]=1;
for(int j=1;j<=18;++j) p[u][j]=p[p[u][j-1]][j-1];
for(int k=head[u];k;k=e[k].next) {
int v=e[k].to; if(v==last) continue;
dfs1(v,u);
if(dep[v]>=dep[u]) dep[u]=dep[v],son[u]=v;
sz[u]+=sz[v];
}
dep[u]++;
}
void dfs2(int u,int tp) {
top[u]=tp;
if(son[u]) dfs2(son[u],tp);
for(int k=head[u];k;k=e[k].next) {
int v=e[k].to; if(v==p[u][0]||v==son[u]) continue;
dfs2(v,v);
}
}
void gao(int u) {
U[u]=new int[dep[u]+1];
D[u]=new int[dep[u]+1];
int cur=u;
for(int i=0;i<=dep[u];++i)
D[u][i]=cur,cur=son[cur];
cur=u;
for(int i=0;i<=dep[u];++i)
U[u][i]=cur,cur=p[cur][0];
}
int Lg[N];
int query(int u,int k) {
if(dis[u]<=k) return 0;
if(!k) return u;
u=p[u][Lg[k]],k-=(1<<Lg[k]);
int td=dis[u]-dis[top[u]];
if(td>=k) return D[top[u]][td-k];
else return U[top[u]][k-td];
}
}
struct Que {
int u,d;
};
vector<Que> s;
int n,q;
int delt[N],del[N];
int ans[N];
void push_down(int u,int last) {
del[u]=(del[last]+del[u])%mod;
ans[u]=(ans[u]+del[u])%mod;
for(int k=head[u];k;k=e[k].next) {
int v=e[k].to; if(v==last) continue;
push_down(v,u);
}
del[u]=0;
}
int get(int v,int u) {
if(__::dis[v]>__::dis[u]) return sz[v];
if(__::dis[v]==__::dis[u]) {
if(v==u) return n;
return sz[v];
}
int t=__::query(u,__::dis[u]-__::dis[v]-1);
if(fa[t]==v) return n-sz[t];
else return sz[v];
}
int main() {
rd(n),rd(q);
int inv=Pow(n,mod-2);
for(int i=1,x,y;i<n;++i) rd(x),rd(y),ad(x,y);
__::dfs1(1,0),__::dfs2(1,1);
for(int i=1;i<=n;++i) if(__::top[i]==i) __::gao(i);
for(int i=2;i<=n;++i) __::Lg[i]=__::Lg[i>>1]+1;
for(int i=1;i<=q;++i) {
int ty,v,d; rd(ty),rd(v);
if(ty==1) {
rd(d);
delt[v]=(delt[v]+d)%mod;
s.PB((Que){v,d});
}
else {
ll t=ans[v];
for(int j=0;j<s.size();++j)
t=(t+get(s[j].u,v)*(ll)s[j].d)%mod;
printf("%lld\n",(t*(ll)inv%mod+mod)%mod);
}
if(s.size()>400) {
for(int u=1;u<=n;++u) if(delt[u]) {
for(int k=head[u];k;k=e[k].next) {
int v=e[k].to; if(v==fa[u]) continue;
del[v]=(del[v]+(n-sz[v])*(ll)delt[u])%mod;
}
del[1]=(del[1]+sz[u]*(ll)delt[u])%mod;
del[u]=(del[u]-sz[u]*(ll)delt[u])%mod;
ans[u]=(ans[u]+n*(ll)delt[u])%mod;
delt[u]=0;
}
push_down(1,0);
s.clear();
}
}
return 0;
}
如果 ∑ d i s ( i , a i ) [ a i ≠ 0 ] > 2 n − 2 \sum dis(i,a_i)[a_i \not= 0] > 2n-2 ∑dis(i,ai)[ai=0]>2n−2必然无解,因为每条边最多能对这个式子产生 2 2 2的贡献。
所以可以暴力遍历 a i a_i ai到 i i i路径上的所有点。
相当于是限制了:
同时我们发现,每个点的所有邻边的相对操作顺序确定,就可以唯一确定最终的 a i a_i ai。
所以对每个点算答案然后乘起来就可以了。
#include
#include
#include
#include
#include
#define PB push_back
#define PII pair
#define MP make_pair
#define fir first
#define sec second
#define ll long long
using namespace std;
template <class T>
inline void rd(T &x) {
x=0; char c=getchar(); int f=1;
while(!isdigit(c)) { if(c=='-') f=-1; c=getchar(); }
while(isdigit(c)) x=x*10-'0'+c,c=getchar(); x*=f;
}
void FAIL() { printf("0"); exit(0); }
const int N=5e5+10,mod=1e9+7;
int In[N],Out[N],To[N],vis[N],n;
int sol(vector<int> &G,vector<PII> &E) {
G.PB(0),G.PB(n+1);
for(int i=0;i<E.size();++i) Out[E[i].fir]++,In[E[i].sec]++,To[E[i].fir]=E[i].sec;
for(int i=0;i<G.size();++i) if(In[G[i]]>1||Out[G[i]]>1) FAIL();
for(int i=0;i<G.size();++i) if(!vis[G[i]]) {
int cur=G[i]; vis[cur]=1;
while(~To[cur]&&!vis[To[cur]]) cur=To[cur],vis[cur]=1;
if(To[cur]==G[i]) FAIL();
}
int cur=0;
while(~To[cur]) cur=To[cur];
if(cur==n+1&&(int)G.size()-(int)E.size()>1) FAIL();
for(int i=0;i<G.size();++i) In[G[i]]=Out[G[i]]=vis[G[i]]=0,To[G[i]]=-1;
return max((int)G.size()-(int)E.size()-2,0);
}
vector<int> G[N];
vector<PII> E[N];
int fa[N],dep[N];
void dfs1(int u,int last) {
fa[u]=last,dep[u]=dep[last]+1;
for(int i=0;i<G[u].size();++i) {
int v=G[u][i]; if(v==last) continue;
dfs1(v,u);
}
}
vector<int> P,Q;
void getpath(int x,int y) {
P.clear(),Q.clear();
int flg=0;
if(dep[x]<dep[y]) swap(x,y),flg=1;
P.PB(x);
while(dep[x]>dep[y]) x=fa[x],P.PB(x);
if(x==y) { if(flg) reverse(P.begin(),P.end()); return; }
Q.PB(y);
while(fa[x]!=fa[y]) x=fa[x],y=fa[y],P.PB(x),Q.PB(y);
P.PB(fa[x]);
for(int i=(int)Q.size()-1;i>=0;--i) P.PB(Q[i]);
if(flg) reverse(P.begin(),P.end());
}
int tot;
int a[N];
int fac[N];
int main() {
rd(n);
for(int i=1,x,y;i<n;++i) rd(x),rd(y),G[x].PB(y),G[y].PB(x);
dfs1(1,0);
for(int i=1;i<=n;++i) rd(a[i]);
for(int i=1;i<=n;++i) if(a[i]) {
if(a[i]==i) FAIL();
getpath(a[i],i);
if((tot+=(int)P.size()-1)>2*n-2) FAIL();
int m=(int)P.size()-1;
E[P[0]].PB(MP(0,P[1]));
E[P[m]].PB(MP(P[m-1],n+1));
for(int i=1;i<m;++i) E[P[i]].PB(MP(P[i-1],P[i+1]));
}
memset(To,-1,sizeof(To));
int ans=1;
fac[0]=1; for(int i=1;i<=n;++i) fac[i]=fac[i-1]*(ll)i%mod;
for(int i=1;i<=n;++i) ans=ans*(ll)fac[sol(G[i],E[i])]%mod;
printf("%d",ans);
return 0;
}