首页 > 代码库 > 0916解题报告

0916解题报告

 

第一题

题目大意:一个n*m的矩形,有k个点不能取,求最大子正方形。

很裸的二维动归,100分没得说的。

 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<ctime> 7 using namespace std; 8 int n,m,p,maxx,flag[1010][1010],f[1010][1010]; 9 namespace INIT10 {11     char buf[1<<15],*fs,*ft;12     inline char getc() {return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;}13     inline int read()14     {15         int x=0,rev=0,ch=getc();16         while(!isdigit(ch)){if(ch==-)rev=1;ch=getc();}17         while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-0;ch=getc();}18         return rev?-x:x;19     }20 }using namespace INIT;21 int Min(int a,int b,int c)22 {23     if(a>b)  a=b;24     if(a>c)  a=c;25     return a;26 }27 int main()28 {29     freopen("papercut.in","r",stdin);30     freopen("papercut.out","w",stdout);31     n=read();  m=read();  p=read();32     for(int i=1;i<=p;i++)33     {34         int x=read(),y=read();35         flag[x][y]=1;36     }37     for(int i=1;i<=n;i++)38         for(int j=1;j<=m;j++)39         {40             if(flag[i][j])  {f[i][j]=0;  continue;}41             f[i][j]=Min(f[i-1][j],f[i][j-1],f[i-1][j-1])+1;42             maxx=max(f[i][j],maxx);43             if(maxx>50)  {printf("50\n");  return 0;}44         }45     printf("%d\n",maxx);46     return 0;47 }

为了对拍,写了一个很弱的暴力

 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<ctime> 6 #include<cmath> 7 #include<algorithm> 8 using namespace std; 9 namespace INIT10 {11     char buf[1<<15],*fs,*ft;12     inline char getc() {return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;}13     inline int read()14     {15         int x=0,rev=0,ch=getc();16         while(!isdigit(ch)){if(ch==-)rev=1;ch=getc();}17         while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-0;ch=getc();}18         return rev?-x:x;19     }20 }using namespace INIT;21 int n,m,p,flag[1010][1010];22 int main()23 {24     freopen("papercut.in","r",stdin);25     freopen("papercut.out","w",stdout);26     n=read();  m=read();  p=read();27     for(int i=1;i<=p;i++)28     {29         int x=read(),y=read();30         flag[x][y]=1;31     }32     for(int i=0;i<=m+1;i++)  flag[0][i]=flag[n+1][i]=1;33     for(int i=0;i<=n+1;i++)  flag[i][0]=flag[i][m+1]=1;34     for(int len=min(n,m);len;len--)35         for(int i=1;i<=n;i++)36             for(int j=1;j<=m;j++)37             {38                 int ff=0;39                 for(int ii=0;ii<len;ii++)40                     for(int jj=0;jj<len;jj++)41                         if(flag[i+ii][j+jj])  ff=1;42                 if(!ff)  {cout<<len<<endl;  return 0;}    43             }44     return 0;45 }

数据生产程序:

 1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 int main() 5 { 6     freopen("papercut.in","w",stdout); 7     srand(time(NULL)); 8     int n=10,m=10,p=rand()%n+1; 9     printf("%d %d %d\n",n,m,p);10     for(int i=1;i<=p;i++)  printf("%d %d\n",rand()%n+1,rand()%m+1);11     return 0;12 }

第二题

题目大意:给定一个全是大写字母的字符串,请求出它有多少个不同的子串。

后缀数组模板题,100分也拿到了。

 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<ctime> 7 #include<algorithm> 8 #define MAXN 50010 9 using namespace std;10 long long T,N,rank[MAXN],sa[MAXN],p[MAXN],tmp[MAXN],cnt[MAXN],height[MAXN];11 char s[MAXN];12 inline long long read()13 {14     long long x=0,f=1;  char ch=getchar();15     while(!isdigit(ch))  {if(ch==-)  f=-1;  ch=getchar();}16     while(isdigit(ch))  {x=x*10+ch-0;  ch=getchar();}17     return x*f;18 }19 long long equ(long long x,long long y,long long l)  {return rank[x]==rank[y]&&rank[x+l]==rank[y+l];}20 void doubling()21 {22     for(long long i=1;i<=N;i++)  rank[i]=s[i],sa[i]=i;23     for(long long pos=0,sig=255,l=0,i;pos<N;sig=pos)24     {25         for(pos=0,i=N-l+1;i<=N;i++)  p[++pos]=i;26         for(i=1;i<=N;i++)  if(sa[i]>l)  p[++pos]=sa[i]-l;27         for(i=1;i<=sig;i++)  cnt[i]=0;28         for(i=1;i<=N;i++)  cnt[rank[i]]++;29         for(i=1;i<=sig;i++)  cnt[i]+=cnt[i-1];30         for(i=N;i;i--)  sa[cnt[rank[p[i]]]--]=p[i];31         for(pos=0,i=1;i<=N;i++)32             tmp[sa[i]]=equ(sa[i],sa[i-1],l)?pos:++pos;33         for(i=1;i<=N;i++)  rank[i]=tmp[i];34         l=!l?1:l<<1;35     }36 }37 void get_height()38 {39     for(long long i=1,j=0,k;i<=N;i++)40     {41         if(!(k=sa[rank[i]-1]))  {j=0;  continue;}42         if(j)  j--;43         while(s[i+j]==s[k+j])  j++;44         height[rank[i]]=j;45     }46 }47 int main()48 {49     freopen("string.in","r",stdin);50     freopen("string.out","w",stdout);51     long long sum=0;52     scanf("%s",s+1);53     N=strlen(s+1);54     doubling();55     get_height();56     for(long long i=1;i<=N;i++)  sum+=N-sa[i]+1-height[i];57     cout<<sum<<endl;58     return 0;59 }

第三题

题目描述:秦新要穿越混乱城邦的区域到大陆最南边的罗德岛,尽管秦新拥有传送术,但是在没有混乱城邦的地图的情况下他不能随意使用。混乱城邦有n个城市,秦新初始时位于1号城市,罗德岛在n号城市,有m条单向道路连接n个城市,每条道路连接不同的城市,通过一条道路需要花费一定的时间。混乱城邦有若干个领主,每个领主境内的城市可以相互到达,每两个可以相互到达的城市一定属于同一个领主。秦新位于哪个城市就可以得到这个城市所属领主所管辖的所有城市的地图(获得地图不花费时间),因此,秦新到达了哪个领主的地区,他就可以不花费任何代价传送到这个领主所管辖的任意一个城市,并且,他获得了可使用k次的神术,神术每次使用可以使他瞬间通过一条道路。秦新现在情况紧急,他请你帮忙求出他到达罗德岛的最短时间。

考场上忘记了tanjar的写法,只好用并查集暴力维护,只拿了10分。

正解:先用tanjar缩点,然后就是树归了。(据说可以用分层图来搞,但是蒟蒻并不知道分层图是什么鬼)

 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<ctime> 7 using namespace std; 8 #define INF 1000000000 9 struct node{int y,next,v;}e[20010],E[20010];10 int n,m,k,len,top,bcnt,now,Link[10010],head[10010],belong[10010],stack[10010],instack[10010],dfn[10010],low[10010],q[1000100],dis[10010],vis[10010],f[10010][6];11 namespace INIT12 {13     char buf[1<<15],*fs,*ft;14     inline char getc() {return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;}15     inline int read()16     {17         int x=0,rev=0,ch=getc();18         while(!isdigit(ch)){if(ch==-)rev=1;ch=getc();}19         while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-0;ch=getc();}20         return rev?-x:x;21     }22 }using namespace INIT;23 void insert(int xx,int yy,int vv)24 {25     e[++len].next=Link[xx];26     Link[xx]=len;27     e[len].y=yy;28     e[len].v=vv;29 }30 void Insert(int xx,int yy,int vv)31 {32     E[++len].next=head[xx];33     head[xx]=len;34     E[len].y=yy;35     E[len].v=vv;36 }37 void tanjar(int x)38 {39     low[x]=dfn[x]=++now;40     stack[++top]=x;41     instack[x]=1;42     int y;43     for(int i=Link[x];i;i=e[i].next)44     {45         y=e[i].y;46         if(!dfn[y])47         {48             tanjar(y);49             low[x]=min(low[x],low[y]);50         }51         else if(instack[y])  low[x]=min(low[x],dfn[y]);52     }53     if(low[x]==dfn[x])54     {55         bcnt++;56         int num=0;57         do58         {59             y=stack[top--];60             instack[y]=0;61             belong[y]=bcnt;62             num++;63         }64         while(x!=y);65     }66 }67 void dp(int x,int y)68 {69     for(int i=head[x];i;i=E[i].next)70     {71         if(f[x][y]+E[i].v<f[E[i].y][y])  {f[E[i].y][y]=f[x][y]+E[i].v;  dp(E[i].y,y);}72         if(f[x][y]<f[E[i].y][y+1]&&y<k)  {f[E[i].y][y+1]=f[x][y];  dp(E[i].y,y+1);}73     }74 }75 int main()76 {77     freopen("trip.in","r",stdin);78     freopen("trip.out","w",stdout);79     n=read();  m=read();  k=read();80     for(int i=1;i<=m;i++)81     {82         int x=read(),y=read(),v=read();83         insert(x,y,v);84     }85     tanjar(1);86     len=0;87     for(int i=1;i<=n;i++)88         for(int j=Link[i];j;j=e[j].next)89             if(belong[i]!=belong[e[j].y])  Insert(belong[i],belong[e[j].y],e[j].v);90     memset(f,10,sizeof(f));  f[belong[1]][0]=0; 91     dp(belong[1],0);92     int minn=999999999;93     for(int i=0;i<=k;i++)  minn=min(minn,f[belong[n]][i]);94     cout<<((minn!=999999999) ? minn : -1)<<endl;95     return 0;96 }

看来我还是很弱,cdc和jjh都AK了,而我只是210,而且在考场上忘记了tanjar的写法。

下一步计划:复习图论、动归。

0916解题报告