(CIRMERGE)
破环成链搞个裸的区间(dp)就行了
//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
typedef long long ll;
const int N=805;
ll f[N][N],sum[N],res=1e18;int a[N],n,T;
ll query(int l,int r){
if(~f[l][r])return f[l][r];
ll res=1e18;
fp(i,l,r-1)cmin(res,query(l,i)+query(i+1,r));
return f[l][r]=res+sum[r]-sum[l-1];
}
int main(){
for(scanf("%d",&T);T;--T){
scanf("%d",&n),res=1e18;
fp(i,1,n<<1)fp(j,i,n<<1)f[i][j]=-1;
fp(i,1,n)scanf("%d",&a[i]),a[i+n]=a[i],f[i][i]=f[i+n][i+n]=0;
fp(i,1,n<<1)sum[i]=sum[i-1]+a[i];
fp(i,1,n)cmin(res,query(i,i+n-1));
printf("%lld
",res);
}
return 0;
}
(GUESSPRM)
一道(zz)题卡了我三天……
首先随便找一个数(x^2>=1e9且x尽量小)问一下,设返回值为d,然后对x^2-d分解质因子,答案就是这些质因子中的一个
然后我们从1到1e9枚举每一个数i,当i^2对这些质因子的模数都不相同时就用这个i去询问
然后没有然后了
//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
typedef long long ll;
const int N=1e5+5;
bitset<N>vis;int p[N],st[N],ok[N],top,m,T;
void init(int n=N-5){
fp(i,2,n){
if(!vis[i])p[++m]=i;
for(R int j=1;j<=m&&1ll*i*p[j]<=n;++j){
vis[i*p[j]]=1;
if(i%p[j]==0)break;
}
}
}
inline int ask(R int x){
printf("1 %d
",x);fflush(stdout);
scanf("%d",&x);return x;
}
inline void query(R int x){
printf("2 %d
",x);fflush(stdout);
char s[5];scanf("%s",s);
}
void div(ll n,int x){
top=0;
n-=x;
for(R int i=1;i<=m&&p[i]<=n;++i)if(n%p[i]==0){
if(p[i]>x)st[++top]=p[i];
while(n%p[i]==0)n/=p[i];
}
if(n>1&&n>x)st[++top]=n;
}
bool ck(R ll x,R int l,R int r){
R int t=x;x*=x;
fp(i,l,r){
if(ok[x%st[i]]){
fp(j,l,i)ok[x%st[j]]=0;
return false;
}
ok[x%st[i]]=st[i];
}
t=ask(t),query(ok[t]);
fp(i,l,r)ok[x%st[i]]=0;
return true;
}
int main(){
init();
for(scanf("%d",&T);T;--T){
int n=31627,x=ask(n);
if(!x){query(n);continue;}
div(1ll*n*n,x);
if(top==1){query(st[top]);continue;}
// bool flag=(st[top]>=(st[top-1]<<1));
if(st[top>1])
fp(i,1,1e9)if(ck(i,1,top))break;
}
return 0;
}
(CHFWAR)
不难发现只有(P)右边那个人能活到最后,所以我们首先要保证他的(A)小于(F)
其次为了方便起见,我们把前面的人做完一轮之后接到后面去,这个的具体细节看代码
那么现在就是从(P+1)开始跑,最多(O(log n))轮就可以跑完,且每一轮只有最后一个人会对(P)造成伤害
所以我们可以暴力模拟这个跑的过程,如果当前剩下的人数(n)(不包括(P)自己)是偶数,那么最后一个人会改变,否则最后一个人不变,但是会对(P)造成伤害。只要模拟这个过程就可以了
//quming
#include<bits/stdc++.h>
#define R register
#define pb push_back
#define inline __inline__ __attribute__((always_inline))
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int N=2e6+5,inf=0x3f3f3f3f;
int a[N],n,f,T,mn,res,top,pos;
int main(){
for(scanf("%d",&T);T;--T){
scanf("%d",&n),mn=pos=inf,top=n-1;
fp(i,1,n-1)scanf("%d",&a[i]);
scanf("%d",&f);
fp(i,1,n-1){
if(a[i]<=f){
res=(i&1?0:a[i-1]);
for(R int k=top-i+1,t=top,s=1;k!=1;k-=(k>>1),s<<=1)
(k&1)?res+=a[t]:t-=s;
if(cmin(mn,res))pos=i;
}
if(i&1)a[++top]=a[i];
}
if(mn!=inf)printf("possible
%d %d
",pos,mn+f);
else puts("impossible");
}
return 0;
}
(CCC)
首先列出转移方程,假设运气最不好,那么敲的顺序必然是从大到小,也就是说我们一开始要把(a_i)给(sort)一下
然后设(f_{i,j})表示考虑前(i)个椰子,敲出了(j)个的最小次数,转移方程为
括号里面是个一次函数的形式,而且我们做的过程中(a_i)是非升的,所以可以用一个类似维护半平面交的方法来维护一次函数
当然直接用李超线段树也没问题
//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int N=1005,inf=0x3f3f3f3f;
int a[N],n,res,z,T,pos,p,mn;
struct node{
int st[N],v[N],top;double px[N],py[N];
inline void clr(){top=0;}
inline double cross(R int i,R int j){return 1.0*(v[i]-v[j])/(st[j]-st[i]);}
inline void ins(R int x,R int y){
while(top>1&&px[top-1]*x+y<=py[top-1])--top;
st[++top]=x,v[top]=y;
if(top>1)px[top-1]=cross(top-1,top),py[top-1]=px[top-1]*x+y;
}
inline int query(R int x){
while(top>1&&x<=px[top-1])--top;
return x*st[top]+v[top];
}
}f[N];
inline bool cmp(const int &x,const int &y){return x>y;}
inline int min(R int x,R int y){return x<y?x:y;}
int main(){
// freopen("testdata.in","r",stdin);
for(scanf("%d",&T);T;--T){
scanf("%d%d",&n,&z),res=0,mn=inf;
fp(i,1,n)scanf("%d",&a[i]);
sort(a+1,a+1+n,cmp);
fp(i,0,z)f[i].clr();f[0].ins(0,0);
fp(i,1,n)fd(j,min(i,z),1)f[j].ins(-i,a[i]*i+f[j-1].query(a[i]));
printf("%d
",f[z].query(0));
}
return 0;
}
(SNKAPT)
裸的费用流
先按时间拆点,每个格子记录每一个时间的果子的最大值,设((i,j,k))表示((i,j))这个格子第(k)个时间点,第(k+1)个时间点的四周的点连边,容(1)费(0),如果停留在原地,就是向((i,j,k+1))连边,容(1),费为(k)时间果子的最大值
然后还有一个比较尴尬的问题就是同一个时间不能有两条蛇在同一个点,老规矩把一个点拆成两个,中间连一条容(1)费(0)的边就行了
其实最尴尬的应该是我忘了费用流怎么打了
//quming
#include<bits/stdc++.h>
#define R register
#define clr(a,x,n) memset(a,x,(n+1)<<2)
#define cpy(a,b,n) memcpy(a,b,(n+1)<<2)
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
#define gg(u) for(int &i=cur[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int N=1e5+5,M=5e5+5,L=265,inf=0x3f3f3f3f;
const int dx[4]={0,1,0,-1},dy[4]={-1,0,1,0};
inline int min(R int x,R int y){return x<y?x:y;}
struct eg{int v,nx,w,c;}e[M];int head[N],tot=1;
inline void add(R int u,R int v,R int w,R int c){
e[++tot]={v,head[u],w,c},head[u]=tot;
e[++tot]={u,head[v],0,-c},head[v]=tot;
}
int dis[N],vis[N],cur[N];
queue<int>q;
int S,T,ans;
bool spfa(){
clr(dis,-1,T),clr(vis,0,T),cpy(cur,head,T);
q.push(T),dis[T]=0,vis[T]=1;
int u;
while(!q.empty()){
u=q.front(),q.pop(),vis[u]=0;
go(u)if(e[i^1].w&&cmax(dis[v],dis[u]-e[i].c)&&!vis[v])
q.push(v),vis[v]=1;
}
return ~dis[S];
}
int dfs(int u,int lim){
if(u==T||!lim)return lim;
int flow=0,f;vis[u]=1;
gg(u)if(dis[v]==dis[u]-e[i].c&&!vis[v]&&(f=dfs(v,min(lim,e[i].w)))){
e[i].w-=f,e[i^1].w+=f,flow+=f,lim-=f;
ans+=f*e[i].c;
if(!lim)break;
}
vis[u]=0;
return flow;
}
inline void zkw(){while(spfa())dfs(S,inf);}
char s[L][L];int mx[L][L][85],id[L][L][85],n,m,z,t,cnt;
int main(){
// freopen("testdata.in","r",stdin);
scanf("%d%d%d%d",&n,&m,&z,&t);
fp(i,1,n)scanf("%s",s[i]+1);
for(R int i=1,x,y,p,q,h;i<=z;++i){
scanf("%d%d%d%d%d",&x,&y,&p,&q,&h);
fp(j,p,q-1)cmax(mx[x][y][j],h);
}
cnt=1;
fp(i,1,n)fp(j,1,m)if(s[i][j]!='#')fp(k,0,t-1){
add(cnt,cnt+1,1,0);
id[i][j][k]=cnt,cnt+=2;
}
S=0,T=cnt;
fp(i,1,n)fp(j,1,m)if(id[i][j][0]){
fp(d,0,3)if(id[i+dx[d]][j+dy[d]][0])
fp(k,0,t-2)add(id[i][j][k]+1,id[i+dx[d]][j+dy[d]][k+1],1,0);
fp(k,0,t-2)add(id[i][j][k]+1,id[i][j][k+1],1,mx[i][j][k]);
add(id[i][j][t-1]+1,T,1,mx[i][j][t-1]);
if(s[i][j]=='S')add(S,id[i][j][0],1,0);
}
zkw();
printf("%d
",ans);
return 0;
}
(LVMFFN)
因为(k=2)非常特殊我们特殊考虑
打表可得,当(k=2)的时候,(n=1 or 3)答案为(m),(n=2)必死,如果(nleq 2m),答案为(m-leftlceil nover 2
ight
ceil),否则只有当(n-2m+1)是(2)的次幂的时候答案为(0),其他全是必死
然后剩下的情况中,首先(1)到(k-1)个人的情况下,(1)号的方案只要自己同意就行,所以最大收益为(m),(k)到(2k-1)的情况下,(1)号只需要用(1)块钱去收买别人就能被同意,最大收益为(m-1),(2k)到(3k-1)时需要(2)块钱收买别人……
即,当(nleq (m+1)k-1)时,最大收益为(m-leftlfloor nover k ight floor)
然后观察后面的情况,发现可以活下来的人越来越稀疏了,且这些活下来的人受益为(0),其他大部分是必死的
我们假设(x)是一个可以活下来的人,(x+p)是下一个可以活下来的人,那么会赞成(x+p)方案的,只有(x+1)到(x+p),以及用那(m)块钱收买的人
记(c=x+ppmod{k}),根据打表可得(c)不可能为(0),也就是说(c)的值为(1)到(k-1)
因为(x+p)可以活下来,所以存在关系
因为这里需要整除,所以(c)的取值是唯一的,那么(p)的取值也是惟一的
这里(x)的初值记为((m+1)k-1),代入之后发现此后(p)的值只与(k)有关,与(m)无关,那么我们可以预处理出所有的(p)和(p)的前缀和,询问的时候判断(n-((m+1)k-1))是否在(p)的前缀和里出现过就行了
当(k=10^5)时,(p)的个数最多,为(2e6)个,直接线性筛即可
//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int N=3e6+5;
typedef long long ll;
int k,T,top,pos;ll n,m,flag,t,st[N],s[N],sum[N];
inline ll calc(R ll n){
if(n<=3)return (n&1)?m:-1;
return m-((n+1)>>1);
}
void solve(){
while(T--){
scanf("%lld%lld",&n,&m);
if(n<=(m<<1))flag=calc(n);
else t=n-(m<<1)+1,flag=((t==(t&-t))?0:-1);
(~flag)?printf("%lld
",flag):puts("Thrown off the roof.");
}
}
int main(){
// freopen("testdata.in","r",stdin);
scanf("%d%d",&k,&T);
if(k==2)return solve(),0;
s[top=1]=k*2-1,st[top]=(s[top]-1)/(k-1),sum[top]=st[top];
while(sum[top]<=1e18){
s[top+1]=s[top]+st[top],
st[top+1]=(s[top+1]-1)/(k-1),
sum[top+1]=sum[top]+st[top+1],
++top;
}
while(T--){
scanf("%lld%lld",&n,&m);
if(1.0*(n+1-k)/k<=m)flag=m-n/k;
else{
t=n-(m*k+k-1);
int pos=lower_bound(sum+1,sum+1+top,t)-sum;
flag=(sum[pos]==t?0:-1);
}
(~flag)?printf("%lld
",flag):puts("Thrown off the roof.");
}
return 0;
}
(MXMN)
首先对两个图分别建出(kruskal)重构树,那么(f(G,i,j)=val(LCA(i,j)))
对于第一棵树,我们把权值查分一下,即记(val'_u=val_u-val_{fa_u},u>n),(val'_u=0,uleq n)。定义一次对(u)的修改操作((uleq n))为将(u)到根节点路径上所有点的(sum_u+=val'_u),定义一次对(u)的查询操作为((uleq n))将(u)到根节点路径上的所有的(sum)求和。不难发现,经过一次对(u)的修改操作之后,对每一个(v)的查询操作得到的结果就是(f(G,u,v))。这两个都可以通过树剖+线段树解决,复杂度(O(nlog^2n))
对于第二棵树,先考虑暴力,即枚举所有的点(u(u>n)),对于(u)的左子树里的点(v(vleq n)),将所有的(v)在第一棵树上修改,然后再对于所有在右子树中的点(v(vleq n)),将所有的(v)查询,记此时总的贡献为(sum),那么(ans+=sum imes val_u)
这个暴力可以用(dsu on tree)优化,复杂度即为(O(nlog^3n))
//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int P=998244353;
inline void swap(R int &x,R int &y){R int t=x;x=y,y=t;}
inline void upd(R int &x,R int y){(x+=y)>=P?x-=P:0;}
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
R int res=1;
for(;y;y>>=1,x=mul(x,x))(y&1)?res=mul(res,x):0;
return res;
}
const int N=5e5+5;
struct EG{
int u,v,w;
inline bool operator <(const EG &b)const{return w<b.w;}
};
struct eg{int v,nx;};
int n,m,ans;
namespace T1{
eg e[N];int head[N],tot;EG E[N];
inline void Add(R int u,R int v){e[++tot]={v,head[u]},head[u]=tot;}
int dfn[N],rk[N],top[N],fa[N],val[N],sz[N],son[N],dep[N],cnt,nd;
void dfs1(int u){
sz[u]=1,dep[u]=dep[fa[u]]+1;
go(u){
fa[v]=u,dfs1(v),sz[u]+=sz[v];
if(sz[v]>sz[son[u]])son[u]=v;
}
}
void dfs2(int u,int t){
top[u]=t,dfn[u]=++cnt,rk[cnt]=u;
if(son[u])dfs2(son[u],t);
go(u)if(!dfn[v])dfs2(v,v);
}
inline int find(R int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
struct node;typedef node* ptr;
struct node{
ptr lc,rc;int s,sum,t;
inline void ppd(R int x){upd(sum,mul(x,s)),t=add(t,x);}
inline void pd(){if(t)lc->ppd(t),rc->ppd(t),t=0;}
inline void up(){sum=add(lc->sum,rc->sum);}
}ee[N<<2],*pp=ee,*rt;
void build(ptr &p,int l,int r){
p=++pp;if(l==r)return p->s=val[rk[l]],void();
int mid=(l+r)>>1;
build(p->lc,l,mid),build(p->rc,mid+1,r);
p->s=add(p->lc->s,p->rc->s);
}
int res;
void qqq(ptr p,int l,int r,int ql,int qr){
if(ql<=l&&qr>=r)return upd(res,p->sum),void();
int mid=(l+r)>>1;p->pd();
if(ql<=mid)qqq(p->lc,l,mid,ql,qr);
if(qr>mid)qqq(p->rc,mid+1,r,ql,qr);
}
void uuu(ptr p,int l,int r,int ql,int qr,int x){
if(ql<=l&&qr>=r)return p->ppd(x),void();
int mid=(l+r)>>1;p->pd();
if(ql<=mid)uuu(p->lc,l,mid,ql,qr,x);
if(qr>mid)uuu(p->rc,mid+1,r,ql,qr,x);
p->up();
}
inline int query(int u){
res=0;
while(u)qqq(rt,1,nd,dfn[top[u]],dfn[u]),u=fa[top[u]];
return res;
}
inline void update(int u,int x){while(u)uuu(rt,1,nd,dfn[top[u]],dfn[u],x),u=fa[top[u]];}
void init(){
fp(i,1,m)scanf("%d%d%d",&E[i].u,&E[i].v,&E[i].w);
sort(E+1,E+1+m);
fp(i,1,n)fa[i]=i;nd=n;
for(R int i=1,u,v;i<=m;++i){
u=find(E[i].u),v=find(E[i].v);
if(u!=v){
val[++nd]=E[i].w,Add(nd,u),Add(nd,v);
fa[u]=fa[v]=fa[nd]=nd;
}
}
fa[nd]=0,dfs1(nd),dfs2(nd,nd);
fp(i,n+1,nd)val[i]=dec(val[i],val[fa[i]]);
build(rt,1,nd);
}
}
namespace T2{
EG E[N];
int ls[N],rs[N],sz[N],fa[N],val[N],nd;
void get(int u){
if(u<=n)return sz[u]=1,void();
fa[ls[u]]=fa[rs[u]]=u,get(ls[u]),get(rs[u]);
sz[u]=sz[ls[u]]+sz[rs[u]];
if(sz[ls[u]]<sz[rs[u]])swap(ls[u],rs[u]);
}
inline int find(R int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
void init(){
fp(i,1,m)scanf("%d%d%d",&E[i].u,&E[i].v,&E[i].w);
sort(E+1,E+1+m);
fp(i,1,n)fa[i]=i;nd=n;
for(R int i=1,u,v;i<=m;++i){
u=find(E[i].u),v=find(E[i].v);
if(u!=v){
val[++nd]=E[i].w,ls[nd]=u,rs[nd]=v;
fa[u]=fa[v]=fa[nd]=nd;
}
}
get(nd);
}
int res;
void query(int u){
if(u<=n)return upd(res,T1::query(u)),void();
query(ls[u]),query(rs[u]);
}
void change(int u,int x){
if(u<=n)return T1::update(u,x),void();
change(ls[u],x),change(rs[u],x);
}
void dfs(int u,int flag){
if(u<=n){
if(flag)change(u,1);
return;
}
dfs(rs[u],0);dfs(ls[u],1);
res=0,query(rs[u]);
upd(ans,mul(val[u],res));
if(flag)change(rs[u],1);else change(ls[u],P-1);
}
}
int main(){
// freopen("testdata.in","r",stdin);
scanf("%d%d",&n,&m);
T1::init(),T2::init(),T2::dfs(T2::nd,1);
printf("%d
",ans);
return 0;
}