好久没来过了。。。。
今天跟一群神犇测TJOI2015day1的题,除了我基本上都Ak了,蒟蒻的只有200分
T1:
http://www.lydsy.com/JudgeOnline/problem.php?id=3996
这题不是很难,就是一个最小割,但是由于没有深入理解矩阵的乘法,结果想了1个小时左右才发现,当Ai,Aj同时为1时才可以获得Bij,而Ai为1又得付出Ci的代价,于是就写掉了
(这题数据真心水,把B的全部加上再减掉C的就可以A了)
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cassert>
#include<iostream>
#include<algorithm>
using namespace std;
const int inf=~0u>>2,maxn=511,maxm=maxn,maxe=maxm*maxm*2;
int tot=1;
int now[maxm],pre[maxe],son[maxe],v[maxe];
void add(int a,int b,int c){pre[++tot]=now[a]; now[a]=tot; son[tot]=b; v[tot]=c;}
void cc(int a,int b,int c){add(a,b,c); add(b,a,c);}
void cc1(int a,int b,int c){add(a,b,c); add(b,a,0);}
int st,ed,n,ans=0,a[maxn];
void init(){
scanf("%d",&n); int x; st=n+1; ed=st+1; memset(a,0,sizeof(a));
for (int i=1;i<=n;++i)
for (int j=1;j<=n;++j)
scanf("%d",&x),cc(i,j,x),a[i]+=x,a[j]+=x,ans-=x;
for (int i=1;i<=n;++i) scanf("%d",&x),cc1(st,i,2*x),cc1(i,ed,a[i]);
}
int dep[maxm];
bool bfs(){
static int q[maxm]; memset(dep,0,sizeof(dep));
int w=1; q[w]=st; dep[st]=1;
for (int i=1;i<=w;++i) for (int p=now[q[i]];p;p=pre[p])
if (v[p] && !dep[son[p]]) q[++w]=son[p],dep[q[w]]=dep[q[i]]+1;
return dep[ed]>0;
}
int find(int x,int f){
if (x==ed) return f; int ans=0;
for (int p=now[x];p;p=pre[p]) if (v[p] && dep[son[p]]>dep[x]){
int k=find(son[p],min(f,v[p]));
v[p]-=k; v[p^1]+=k; f-=k; ans+=k;
if (!f) return ans;
}
dep[x]=0; return ans;
}
int maxflow(){
int ans=0;
while (bfs()) ans+=find(st,inf);
return ans;
}
void work(){
printf("%d\n",-(ans+maxflow()/2));
}
int main(){
init();
work();
fclose(stdin); fclose(stdout);
return 0;
}
T2:
http://www.lydsy.com/JudgeOnline/problem.php?id=3997
这题刚看到就YY了一个50分暴力,后来就进了第三题这个坑,最后这题就没写了
这题的话有两种做法
因为只能向下或者向右,我们设w[i*m+j]=a[i][j],h[i*m+j]=j,那么原题的就可以看成一个导弹拦截问题,w[i]代表这个位置上的导弹数,h[i]代表这个位置导弹的高度,那么
(在执行以下操作的过程中s[x]代表以x结尾的拦截还剩几个)
1、先将数量为0的导弹删掉
2、枚举每个点x
3、找到它前面第一个不比它高的最高的导弹a(找不到就到第4步),如果s[a]>=s[x],那么s[a]-=s[x](拦截完a后就拦截x),然后去第5步,否则s[x]-=s[a],把a删掉(从a出来的已经没有了),继续搞第3步
4、把答案加上s[x](表示要从x开始s[x]个拦截),去第5步
5、s[x]=w[x],然后去第2步
显然枚举每个点的时候,出了删点的过程,最多只会找到一个点,而每个点又只会被删一次,那么就是O(点数)的,但是还要找点删点,可以用个set维护,就是O(点数log点数)的,即O(n^2logn),这个已经可以过了,但是因为这题的特殊性质,可以优化到O(n^2)的,具体参见代码
还有一种很巧妙的做法,最小链覆盖=最长反链,先考虑每个格子只有0或者1,另x1<=x2的偏序关系就是(x1<x2 && y1<=y2) || x1==x2,那么反链就是x1<x2 && y1>y2,就是从右上到左下Dp一遍就行了,现在一个格子中有了多个,那么,另x1<=x2的偏序关系是(x1<x2 && y1<=y2) || (x1==x2 && y1!=y2),那么反链就是(x1<x2 && y1>y2) || (x1==x2 && y1==y2),于是惊讶的发现就是一个带权的Dp了,就O(n^2)了
前一种方法太神了没敢写,于是贴某Ak爷代码
O(n^2logn)
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cassert>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<map>
using namespace std;
typedef long long int64;
const int maxn=1000010;
int h[maxn],t[maxn];
int q,sum,n,m;
void init(){
scanf("%d%d",&n,&m); sum=0;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j){
int v; scanf("%d",&v);
if(v) ++sum,h[sum]=j,t[sum]=v;
}
}
typedef multimap<int,int>::iterator iter;
multimap<int,int> s; int f[maxn];
void solve(){
int64 ans=0; s.clear();
memset(f,0,sizeof(f));
for(int i=1;i<=sum;++i){
for(iter x;f[i]<t[i];){
x=s.upper_bound(h[i]); if(x==s.begin()) break;
--x; int k=min(f[x->second],t[i]-f[i]);
f[x->second]-=k,f[i]+=k;
if(!f[x->second]) s.erase(x);
}
if(f[i]<t[i]) ans+=t[i]-f[i],f[i]=t[i];
s.insert(make_pair(h[i],i));
}
cout<<ans<<endl;
}
int main(){
for(scanf("%d",&q);q--;){
init();
solve();
}
return 0;
}
优化后变成了O(n^2) orz
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cassert>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<map>
using namespace std;
const int maxbuf=20000000;
char buf[maxbuf],*wbuf=buf;
inline int getint(){
int x=0; for(;!isdigit(*wbuf);++wbuf);
while(isdigit(*wbuf)) x=x*10+*wbuf++-'0'; return x;
}
typedef long long int64;
const int maxn=1010;
int64 f[maxn],g[maxn];
int q,n,m;
int main(){
fread(buf,1,maxbuf,stdin);
for(int q=getint();q--;){
n=getint(),m=getint();
memset(f,0,sizeof(f)); int64 ans=0;
for(int i=1;i<=n;++i){
int64 sum=0;
memset(g,0,sizeof(g));
for(int j=1;j<=m;++j){
int v=getint(); sum+=f[j];
if(f[j]>v) continue;
g[j]=min(sum,v-f[j]);
if(v>sum) ans+=v-sum,sum=v;
f[j]=v;
}
for(int j=m,k=m-1;j>=1;--j){
if(k>=j) k=j-1;
for(;k;--k){
int64 v=min(g[j],f[k]);
g[j]-=v,f[k]-=v;
if(!g[j]) break;
}
}
}
cout<<ans<<endl;
}
return 0;
}
第二种方法
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cassert>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1011,maxbuf=20000000;
char buf[maxbuf],*wbuf=buf;
inline void read(int &x){
x=0; while (!isdigit(*wbuf)) ++wbuf;
while (isdigit(*wbuf)) x=x*10+*wbuf++-'0';
}
int a[maxn][maxn],f[maxn][maxn],n,m;
void init(){
read(n); read(m);
for (int i=1;i<=n;++i) for (int j=1;j<=m;++j)
read(a[i][j]);
}
void work(){
for (int i=1;i<=m;++i) f[0][i]=0;
for (int i=1;i<=n;++i) f[i][m+1]=0;
for (int i=1;i<=n;++i) for (int j=m;j>=1;--j)
f[i][j]=max(max(f[i-1][j+1]+a[i][j],f[i-1][j]),f[i][j+1]);
cout<<f[n][1]<<endl;
}
int main(){
fread(buf,1,maxbuf,stdin);
int T; read(T);
while (T--) init(),work();
return 0;
}
T3:
http://www.lydsy.com/JudgeOnline/problem.php?id=3998
这题要求有关子串,就知道是后缀自动机,但是因为太弱了,后缀自动机写不出啊,于是就傻叉的写了后缀数组,虽然测试A掉了,但是bzoj交到死也TLE(某大神硬是DC3搞过去了orz)
先来讲一下后缀数组的写法吧,对于T=0的就是个论文题,来讲讲T=1的情况
首先按照后缀的排序枚举每个后缀
看这个后缀在所有子串中的排名,如果<rank就继续枚举,如果>=rank就二分一下在什么位置
统计的时候,要注意把下面与其相同的部分也统计掉,然后乱二分几下,就变成了O(nlogn)的了
后缀自动机果然还是得写啊。。。
死都TLE的
#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<cassert>
#include<iostream>
#include<algorithm>
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
const int maxn=500011;
typedef long long LL;
char s[maxn]; int op,rk,n;
void init(){
scanf("%s%d%d",s,&op,&rk); n=strlen(s)+1;
}
int sa[maxn],rank[maxn],height[maxn];
inline bool cmp(int *x,int a,int b,int len){return x[a]==x[b] && x[a+len]==x[b+len];}
void suffix_sort(){
static int wx[maxn],ws[maxn],wy[maxn];
int i,m=300,*x=wx,*y=wy;
for (i=0;i<m;++i) ws[i]=0;
for (i=0;i<n;++i) ++ws[x[i]=s[i]];
for (i=1;i<m;++i) ws[i]+=ws[i-1];
for (i=n-1;i>=0;--i) sa[--ws[x[i]]]=i;
for (int len=1,p=0;p<n;len<<=1,m=p){
for (p=0,i=n-len;i<n;++i) y[p++]=i;
for (i=0;i<n;++i) if (sa[i]>=len) y[p++]=sa[i]-len;
for (i=0;i<m;++i) ws[i]=0;
for (i=0;i<n;++i) ++ws[x[y[i]]];
for (i=1;i<m;++i) ws[i]+=ws[i-1];
for (i=n-1;i>=0;--i) sa[--ws[x[y[i]]]]=y[i];
for (swap(x,y),x[sa[0]]=0,i=p=1;i<n;++i) // y is rank
x[sa[i]]=cmp(y,sa[i-1],sa[i],len)?p-1:p++;
}
for (int i=0;i<n;++i) rank[i]=x[i];
}
void get_height(){
for (int i=0,j,len=0;i<n-1;height[rank[i++]]=len)
for (len?--len:0,j=sa[rank[i]-1];s[i+len]==s[j+len];++len);
}
int rmq[maxn][22],lg2[maxn];
void RMQ(){
lg2[1]=0; for (int i=2;i<=n;++i) lg2[i]=lg2[i>>1]+1;
for (int i=n-1;i>=1;--i){
rmq[i][0]=height[i]; int x=lg2[n-i];
for (int j=1;j<=x;++j)
rmq[i][j]=min(rmq[i][j-1],rmq[i+(1<<(j-1))][j-1]);
}
}
int Rget(int a,int b){
int x=lg2[b-a+1];
return min(rmq[a][x],rmq[b-(1<<x)+1][x]);
}
void prepare(){suffix_sort(); get_height(); RMQ();}
LL f[maxn];
LL Query(int s,int x){
if (s==height[x]) return f[x];
int t=x+1,w=n;
while (t<=w){
int mid=(t+w)>>1;
if (Rget(x+1,mid)<s) w=mid-1;
else t=mid+1;
}
++w; return (LL)s*(w-x)+f[w];
}
LL Query2(int s,int x){
int t=x,w=n;
while (t<=w){
int mid=(t+w)>>1;
if (Rget(x,mid)<s) w=mid-1;
else t=mid+1;
}
++w; return (LL)s*(w-x)+f[w];
}
void write(int a,int len){
for (int i=0;i<len;++i) putchar(s[a+i]); putchar('\n');
}
void work(){
prepare(); --n;
if (!op){
for (int i=1;i<=n;++i){
int sum=n-sa[i]-height[i];
if (rk>sum) rk-=sum;
else{write(sa[i],height[i]+rk); return;}
}
puts("-1"); return;
}
f[n+1]=0;
for (int i=n;i>=1;--i){
f[i]=Query2(height[i],i+1)+height[i];
}
for (int i=1;i<=n;++i){
int len=n-sa[i]; LL tmp=f[i],res=Query(len,i)-tmp;
if (rk>res) rk-=res;
else{
int t=height[i]+1,w=len;
while (t<=w){
int mid=(t+w)>>1;
if (Query(mid,i)-tmp>=rk) w=mid-1;
else t=mid+1;
}
write(sa[i],w+1); return;
}
}
puts("-1"); return;
}
int main(){
freopen("string.in","r",stdin);
freopen("string.out","w",stdout);
init();
work();
fclose(stdin); fclose(stdout);
return 0;
}
DC3的 orz
#include<bits/stdc++.h>
using namespace std;
#define X first
#define Y second
#define mp make_pair
#define ph push
#define pb push_back
#define REP(i,a,n) for(int _tmp=n,i=a;i<=_tmp;++i)
#define DEP(i,a,n) for(int _tmp=n,i=a;i>=_tmp;--i)
#define rep(i,a,n) for(int i=(a);i<=(n);++i)
#define dep(i,a,n) for(int i=(a);i>=(n);--i)
#define ALL(x,S) for(__typeof((S).end()) x=S.begin();x!=S.end();x++)
#define eps 1e-8
#define pi 3.1415926535897
#define sqr(x) ((x)*(x))
#define MAX(a,b) a=max(a,b)
#define MIN(a,b) a=min(a,b)
#define SZ(x) ((int)(x).size())
#define CPY(a,b) memcpy(a,b,sizeof(a))
#define CLR(a) memset(a,0,sizeof(a))
#define POSIN(x,y) (1<=(x)&&(x)<=n&&1<=(y)&&(y)<=m)
#define all(x) (x).begin(),(x).end()
#define COUT(S,x) cout<<fixed<<setprecision(x)<<S<<endl
typedef long long ll;
typedef double lf;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<lf,lf> pff;
typedef complex<double> CD;
const int inf=0x20202020;
const int mod=1000000007;
template<class T> inline void read(T&x){bool fu=0;char c;for(c=getchar();c<=32;c=getchar());if(c=='-')fu=1,c=getchar();for(x=0;c>32;c=getchar())x=x*10+c-'0';if(fu)x=-x;};
template<class T> inline void read(T&x,T&y){read(x);read(y);}
template<class T> inline void read(T&x,T&y,T&z){read(x);read(y);read(z);}
template<class T> inline void read(T&x,T&y,T&z,T&q){read(x);read(y);read(z);read(q);}
const int DX[]={1,0,-1,0},DY[]={0,1,0,-1};
ll powmod(ll a,ll b) {ll res=1;a%=mod;for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
ll powmod(ll a,ll b,ll mod) {ll res=1;a%=mod;for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
//*******************************************
#define rank orzlyd
const int N=511111,M=111111;
int l,m,n,C;
char s[N],asks[N];
int rank[N],rank2[N],pai[N],sa[N],rmq[22][N],height[N];
ll h[N],x,y,hh[N];
/*
namespace SA{
int *x=rank,*y=rank2,*t;
bool cmp(int *y,int a1,int a2, int a3){return y[a1]==y[a2]&&y[a1+a3]==y[a2+a3];}
bool scmp(const int &a, const int &b){return x[a]<x[b];}
void calcsa(){
int j=1,p=1,m=20010;
rep(i,1,n) pai[i]=i,x[i]=s[i];
sort(pai+1,pai+n+1,scmp);
rep(i,1,n) sa[i]=pai[i+1];
for(;j<=n;j*=2,m=p){
p=1;rep(i,n-j,n-1) y[p++]=i;
rep(i,1,n) if(sa[i]>j) y[p++]=sa[i]-j;
rep(i,1,m) pai[i]=0;
rep(i,1,n) ++pai[x[y[i]]];
rep(i,2,m) pai[i]+=pai[i-1];
dep(i,n,1) sa[pai[x[y[i]]]--]=y[i];
t=x;x=y;y=t;p=2;x[sa[1]]=1;
rep(i,2,n) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
}
void calch(){
int i,j,k=0;rep(i,0,n) rank[sa[i]]=i;
for(i=1;i<=n;h[rank[i++]]=k) for(k?k--:0,j=sa[rank[i]-1];s[i+k]==s[j+k];k++);
}
}
*/
namespace SAA{
void init()
{
int *x = rank, *y = height;
static int w[N];
for (int i = 1; i <= n; ++i)
++w[x[i] = s[i] - 96];
for (int i = 2; i <= 126; ++i)
w[i] += w[i - 1];
for (int i = 1; i <= n; ++i)
sa[w[x[i]]--] = i;
for (int k = 1, m = 126; k < n; k <<= 1, swap(x, y))
{
int t = 0;
for (int i = n - k + 1; i <= n; ++i)
y[++t] = i;
for (int i = 1; i <= n; ++i)
if (sa[i] - k >= 1)
y[++t] = sa[i] - k;
memset(w + 1, 0, m << 2);
for (int i = 1; i <= n; ++i)
++w[x[i]];
for (int i = 2; i <= m; ++i)
w[i] += w[i - 1];
for (int i = n; i; --i)
sa[w[x[y[i]]]--] = y[i];
m = 0;
for (int i = 1; i <= n; ++i)
{
int u = sa[i], v = sa[i - 1];
y[u] = i == 1 || x[u] != x[v] || x[u + k] != x[v + k] ? ++m : m;
}
if (m == n)
break;
}
if (y != rank)
memcpy(rank + 1, y + 1, n << 2);
for (int i = 1, h = 0; i <= n; ++i)
{
if (h)
--h;
int j = sa[rank[i] - 1];
while (s[i + h] == s[j + h])
++h;
height[rank[i]] = h;
}
}
}
int LOG[N];
inline int RMQ(const int &l,const int &r){
if(l>r)return inf;
int p=LOG[r-l+1];
return min(rmq[p][l],rmq[p][r-(1<<p)+1]);
}
ll ta[N],tb[N],tp;
int main(){
//ios::sync_with_stdio(false);
freopen("string.in","r",stdin);freopen("string.out","w",stdout);
rep(i,1,20)LOG[1<<i]=i;
rep(i,2,500000)if(!LOG[i])LOG[i]=LOG[i-1];
for(s[1]=getchar();s[1]<'a'||s[1]>'z';s[1]=getchar());n=1;
for(;s[n]>='a'&&s[n]<='z';s[++n]=getchar());s[n]=0;--n;
//printf("%d %s\n",n,s+1);
//SA::calcsa();SA::calch();
SAA::init();rep(i,1,n)h[i]=height[i];
//rep(i,1,n)printf("%d %d %lld\n",i,sa[i],h[i]);
++n;
rep(i,1,n)rmq[0][i]=h[i];
rep(i,1,20)rep(j,1,n){
if(j+(1<<i-1)>n)break;
rmq[i][j]=min(rmq[i-1][j],rmq[i-1][j+(1<<i-1)]);
}
//return 0;
//printf("%d\n",clock());
read(x,y);
if(x==0){
h[0]=0;
rep(i,1,n)h[i]=h[i-1]+(n-sa[i])-h[i];
int Min=1,Max=n,pt,len;
while(Min<Max){
int mid=Min+Max>>1;if(h[mid]<y)Min=mid+1;else Max=mid;
}
if(Min==n){puts("-1");return 0;}
pt=Min;len=y-h[pt-1]+rmq[0][pt]-1;pt=sa[Min];
rep(i,pt,pt+len)putchar(s[i]);puts("");
}else{
if(y>n*(n-1)/2){puts("-1");return 0;}
ll res=0;tp=0;
dep(i,n,1){
while(tp&&h[ta[tp]]>=h[i])--tp;ta[++tp]=i;tb[tp]=hh[i-1]=tb[tp-1]+(ta[tp-1]-i)*h[i];
}
//rep(i,1,n)printf("%d %d %lld %lld\n",i,sa[i],h[i],hh[i]);
ll sum=0;
rep(i,1,n){
sum+=(n-sa[i]);if(sum+hh[i]>=y){
int pos;
dep(j,n-sa[i],1){
int Min=i,Max=n,pt,len;
while(Min<Max){
int mid=Min+Max+1>>1;if(RMQ(i+1,mid)>=j)Min=mid;else Max=mid-1;
}
//printf("%d-%d\n",j,Min);
y+=Min-i+1;
if(sum+hh[i]<y){pos=j;break;}
}
rep(j,sa[i],sa[i]+pos-1)putchar(s[j]);
//printf("%d %d\n",i,pos);
break;
}
}
}
//printf("\n%d\n",clock());
return 0;
}
自动机的
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cassert>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=500011;
char s[maxn]; int op,rank;
void init(){
scanf("%s%d%d",s,&op,&rank);
}
struct Tsam{
struct node{
node *ch[26],*f; int ml,s,sz; LL sum;
int get(int op){return op?sum:sz;}
void clear(){memset(ch,0,sizeof(ch)); f=0; ml=s=0; sz=1; sum=0;}
}e[maxn<<1],*root,*last;
int tot;
node *newnode(){e[tot].clear(); return &e[tot++];}
void clear(){tot=0; last=root=newnode();}
void ins(int c){
node *np=newnode(),*p=last; np->ml=p->ml+1; np->s=1;
for (last=np;p && !p->ch[c];p=p->f) p->ch[c]=np;
if (!p) {np->f=root; return;} node *q=p->ch[c];
if (p->ml+1==q->ml){np->f=q; return;}
node *r=newnode(); *r=*q; r->ml=p->ml+1; r->s=0;
for (np->f=q->f=r;p && p->ch[c]==q;p=p->f) p->ch[c]=r;
}
void Dp(){
static node *q[maxn<<1]; q[1]=root;
static int ws[maxn<<1]; memset(ws,0,sizeof(ws));
for (int i=0;i<tot;++i) ++ws[e[i].ml];
for (int i=1;i<=tot;++i) ws[i]+=ws[i-1];
for (int i=0;i<tot;++i) q[ws[e[i].ml]--]=e+i;
for (int i=tot;i>=1;--i){
q[i]->sum+=q[i]->s;
for (int c=0;c<26;++c) if (q[i]->ch[c])
q[i]->sz+=q[i]->ch[c]->sz,q[i]->sum+=q[i]->ch[c]->sum;
if (q[i]->f) q[i]->f->s+=q[i]->s;
}
}
void getans(int op,int rank){
Dp(); rank+=op?root->s:1;
if (root->get(op)<rank){puts("-1"); return;}
for (node *p=root;;){
rank-=op?p->s:1; if (!rank) return;
for (int c=0;c<26;++c) if (p->ch[c]){
int tmp=p->ch[c]->get(op);
if (tmp<rank) rank-=tmp;
else {putchar('a'+c); p=p->ch[c]; break;}
}
}
}
}sam;
void work(){
sam.clear(); for (int i=0;s[i];++i) sam.ins(s[i]-'a');
sam.getans(op,rank);
}
int main(){
init();
work();
return 0;
}
在看到第一题的时候,没有很快想出模型,第二题也是根本没有想到Dilworth定理(导弹拦截的模型转化也没想到),第三题虽然过了,但是改了太久,主要是因为把数组的意义搞混乱了,以后要注意数组的真实含义