Test on 2016/09/26
T1:小明剪纸(papercut)
小明是个节俭的好孩纸,一天,他在地上捡到了一张n*m的长方形报纸,在仔细观察后他发现报纸上有p个破洞,小明想从报纸上剪出一个完整的最大的正方形,请编程计算这张报纸能剪出的最大正方形。
输入格式:第一行是三个整数:n,m,p。下面p行每行两个整数x,y,表示有一个破洞的位置在(x,y);
输出格式:一个整数表示能剪出的最大正方形;
样例:
Input:
2 3 2
1 1
2 3
Output:
1
数据范围:
数据60% 2<=n,m<=100;
100% 2<=n,m<=1000, 0<=p<=n*m;
由于某些原因,答案的大小<=50,即:答案如果大于50,输出50即可;
简单dp,然而dp不会
在网上搜题解,不知道为啥爆零。
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 int n,m,a[1010][1010]; 5 int ans=0; 6 int p,x,y; 7 int min(int a,int b,int c) 8 { 9 int m=a; 10 if(b<m) m=b; 11 if(c<m) m=c; 12 return m; 13 } 14 int main() 15 { 16 freopen("papercut.in","r",stdin); 17 freopen("papercut.out","w",stdin); 18 cin>>n>>m>>p; 19 for(int i=0;i<n;i++) 20 for(int j=0;j<m;j++) 21 a[i][j]=1; 22 for(int i=1;i<=p;i++) 23 { 24 cin>>x>>y; 25 a[x-1][y-1]=0; 26 } 27 for(int i=1;i<n;i++) 28 for(int j=1;j<m;j++) 29 if(a[i][j]==1) 30 { 31 a[i][j]=min(a[i-1][j],a[i][j-1],a[i-1][j-1])+1; 32 if(a[i][j]>ans) ans=a[i][j]; 33 } 34 if(ans>50) ans=50; 35 cout<<ans<<endl; 36 fclose(stdout); 37 fclose(stdout); 38 return 0; 39 }
字符串(string)
给定一个全是大写字母的字符串,请求出它有多少个不同的子串;
样例:
Input:
CCCCC
Output:
5
Input:
ABABA
Output:
9
数据范围:
设字符串长度为n
100%n<=50000
70%n<=1000
40%n<=100
每个子串一定是某个后缀的前缀,那么原问题等价于求所有后缀之间的不相同的前缀的个数。如果所有的后缀按照 suffix(sa[1]),suffix(sa[2]),suffix(sa[3]),……,suffix(sa[n])的顺序计算,不难发现,对于每 一次新加进来的后缀suffix(sa[k]),它将产生n-sa[k]+1个新的前缀。但是其中有height[k]个是和前面的字符串的前缀是相同 的。所以suffix(sa[k])将“贡献”出n-sa[k]+1-height[k]个不同的子串。累加后便是原问题的答案。这个做法的时间复杂度为 O(n)。
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 }
旅行(trip)
秦新要穿越混乱城邦的区域到大陆最南边的罗德岛,尽管秦新拥有传送术,但是在没有混乱城邦的地图的情况下他不能随意使用。混乱城邦有n个城市,秦新初始时位于1号城市,罗德岛在n号城市,有m条单向道路连接n个城市,每条道路连接不同的城市,通过一条道路需要花费一定的时间。混乱城邦有若干个领主,每个领主境内的城市可以相互到达,每两个可以相互到达的城市一定属于同一个领主。秦新位于哪个城市就可以得到这个城市所属领主所管辖的所有城市的地图(获得地图不花费时间),因此,秦新到达了哪个领主的地区,他就可以不花费任何代价传送到这个领主所管辖的任意一个城市,并且,他获得了可使用k次的神术,神术每次使用可以使他瞬间通过一条道路。
秦新现在情况紧急,他请你帮忙求出他到达罗德岛的最短时间。
输入说明:第一行n,m,k三个整数
后面m行每行3个整数x,y,v,表示有一条道路从x城市出发到y城市需花费v单位时间;
输出说明:一行一个整数,表示花费的最少时间,若无法到达n城市,输出-1;
样例1:
Input:
4 5 0
1 2 3
2 1 3
1 3 1
3 2 2
2 4 4
Output:
4
样例2:
Input:
4 5 1
1 2 3
1 3 3
3 2 3
2 4 3
4 2 3
Output:
0
样例1说明:1,2,3三个城市属于一个领主,4号城市属于另一个领主,秦新可以使用传送术,直接到达2城市,再通过一条2->4的道路即可;
样例2说明:2,4属于同一领主,秦新使用神术通过1->2的道路再传送到4号城市即可;
数据范围:
100%
1<=n,m<=10000
0<=k<=5
60%
1<=n,m<=1000
0<=k<=1
30%
1<=n,m<=100
k=0
缩点+SPFA(or dij)+动归;
缩点上,O(n)的tarjan足以应对,加上数据比较小,O(n^2)的暴力不是不可以敲的;
SPFA,入门级别的,只要学了,应该都能敲出来;
动规上,设f[i][j]为到i节点是使用了j次,然后用SPFA转移;
oj上第三页有一个翻修道路,仅比此题少了一个缩点,但多了堆优化dij,可以看看;
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 using namespace std; 7 int read(){int z=0,mark=1; char ch=getchar(); 8 while(ch<'0'||ch>'9'){if(ch=='-')mark=-1; ch=getchar();} 9 while(ch>='0'&&ch<='9'){z=(z<<3)+(z<<1)+ch-'0'; ch=getchar();} 10 return z*mark; 11 } 12 struct ddd{int next,y,value;}e[21000];int LINK[11000],ltop=0; 13 inline void insert(int x,int y,int z){e[++ltop].next=LINK[x];LINK[x]=ltop;e[ltop].y=y;e[ltop].value=z;} 14 ddd de[21000];int dLINK[11000],dltop=0; 15 inline void dinsert(int x,int y,int z){de[++dltop].next=dLINK[x];dLINK[x]=dltop;de[dltop].y=y;de[dltop].value=z;} 16 int n,m,t; 17 int dfn[11000],low[11000]; 18 bool visited[11000]; 19 int bu=0; 20 int zhan[11000],top=0; 21 int group[11000],id=0,ge[11000]; 22 int f[11000][6]; 23 void tarjian(int x,int father){ 24 visited[x]=true; 25 zhan[++top]=x; low[x]=dfn[x]=++bu; 26 for(int i=LINK[x];i;i=e[i].next){ 27 int y=e[i].y; 28 if(!dfn[y]){ tarjian(y,x); low[x]=min(low[x],low[y]);} 29 else if(visited[y]) low[x]=min(low[x],dfn[y]); 30 } 31 if(dfn[x]==low[x]){ 32 id++; 33 int temp; 34 do{ 35 temp=zhan[top--]; 36 visited[temp]=false; 37 group[temp]=id; 38 ge[id]++; 39 }while(temp!=x); 40 } 41 } 42 void dp_map(int x,int y){ 43 for(int i=dLINK[x];i;i=de[i].next){ 44 if(f[x][y]+de[i].value < f[de[i].y][y]){ f[de[i].y][y]=f[x][y]+de[i].value; dp_map(de[i].y,y);} 45 if(f[x][y] < f[de[i].y][y+1] && y<t){ f[de[i].y][y+1]=f[x][y]; dp_map(de[i].y,y+1);} 46 } 47 } 48 int main(){//freopen("ddd.in","r",stdin); 49 freopen("trip.in","r",stdin); 50 freopen("trip.out","w",stdout); 51 memset(visited,0,sizeof(visited)); 52 memset(f,10,sizeof(f)); 53 cin>>n>>m>>t; 54 int _left,_right,_value; 55 while(m --> 0){//趋向于 56 _left=read(),_right=read(),_value=read(); 57 insert(_left,_right,_value); 58 } 59 tarjian(1,0); 60 for(int i=1;i<=n;i++) 61 for(int j=LINK[i];j;j=e[j].next)if(group[i]!=group[e[j].y]) 62 dinsert(group[i],group[e[j].y],e[j].value); 63 f[group[1]][0]=0; 64 dp_map(group[1],0); 65 int minn=999999999; 66 for(int i=0;i<=t;i++) minn=min(minn,f[group[n]][i]); 67 cout<<((minn!=999999999) ? minn : -1)<<endl; 68 return 0; 69 }