2016.11.2第57套模拟集训三

1.神秘大门
(door.pas/c/cpp)
【题目描述】
最近小K大牛经过调查发现,在WZland的最南方——WZ Antarctica 出现了奇怪
的磁场反应。为了弄清楚这一现象,小K 大牛亲自出马,来到了WZ Antarctica。
小K大牛发现WZ Antarctica 出现了一道神秘的大门。人总有好奇心,小K大牛想打开
这扇神秘大门,看门的后面究竟是什么东西,但用尽什么办法也不能打开这扇门。
突然,门上出现了一些奇怪的字符。凭着敏锐的直觉,小K 认为这些符号就是打
开这扇门的关键, 于是小K 抓紧时间开始研究这些符号。
经过一些时间的研究,小K 大牛发现这些符号其实是一串密码,只有破解了
这个密码, 才能打开那扇神秘大门。这个密码十分简单,他给出了两个很长的字
符串A 和B,你只需要判断B 是否在A 中出现过就可以了,当然如果B 在A
中出现,那么你还需要输出B 的字符在A 中依次出现的位置。
这里解释一下B 在A 中出现的概念,设A=S1S2…SN,B= T1T2…TM,如果存
在一组数K:K1<K2<…<KM,使得B=SK1SK2…SKM,那么就可以认为B 在A 出现
过。比如说A=sdfesad, B=sfsad,那么B 在A 中出现过,因为B 中的字符在A
中依次出现的位置为1 3 5 6 7。
这个解密过程实在太简单了,于是小K 大牛就将这个任务交给了你。由于小K
大牛十分着急,他只给了你1s 的时间。
【输入】
输入数据包含2 行,分别包含一个字符串,第一行输入的是字符串A,第二
行输入的是字符串B。

【输出】
第一行输出一个字符串“Yes”或“No”,如果B 在A 中出现,那么输出“Yes”,
否则输出“No”。
如果你的第一行输出“Yes”,那么在第接下来若干行你需要输出一组数K,使
得B=SK1SK2…SKM,每行一个数;否则第二行为空。如果存在多组数据满足条件,
你需要输出字典序最大的一组。
【输入输出样例1】
door.in        door.out
sdfesad       Yes
sfsad          1
                  3
                  5
                  6
                  7
【输入输出样例2】
door.in        door.out
abcdef         No
acdefg

题解:

第一题啊,简单的我以为我最开始想少了。就是从后往前扫,扫到了就输出return ; o(N)。easy

#include<iostream>
#include<cstdio>
#include<cstring>
#define MN 10000005
using namespace std;
char a[MN],b[MN];
int pos[MN],lena,lenb;
void readin()
{
    cin>>a;
    cin>>b;
    lena=strlen(a);
    lenb=strlen(b);
}
void work()
{
    int j=lenb-1;
    for(int i=lena-1;i>=0;i--)
    if(a[i]==b[j])
    {
        pos[j]=i+1;
        j--;
        if(j==-1) return ;
    }
}
void prin()
{
    if(pos[0]==0) {cout<<"No"<<endl; return ;}
    cout<<"Yes"<<endl;
    for(int i=0;i<lenb;i++) cout<<pos[i]<<endl;
    return ;
}
int main()
{
    freopen("door.in","r",stdin);
    freopen("door.out","w",stdout);
    readin();
    work();
    prin();
    return 0;
}

2. 集结蚂蚁
(ant.c/cpp/pas)
【题目描述】
雄心勃勃的企业家达伦·克劳斯发现了皮姆博士有关缩小原子间距离的公式并
研发出新一代微型“黄蜂战士”,皮姆博士担忧武器会引发不可挽回的后果,于是
找到斯科特并使他成为了新一代“蚁人”。正逢克劳斯与外商交易黄蜂战衣的那天,
斯科特受命前往摧毁黄蜂战衣并销毁数据,然而一个人的力量是渺小的,斯科特需
要走入一个巨大的蚁穴去召唤蚂蚁与他共同作战。
蚁穴是一个巨大复杂的地带,由n 行m 列组成,每个偶数行存在至少一个蚂蚁
聚集地,同一行的不同蚂蚁聚集地以一堵墙隔开,每个蚂蚁聚集地的大小为Si;
每个奇数行存在连接相邻偶数行中蚂蚁聚集地的路径,一个蚂蚁聚集地可能有多条
路径可以到达。
蚁人可从蚁穴的第一行任何一路口出发,由于时间紧迫,蚁人只能向下一行走,
在这种情况下,蚁人希望你能告诉他如何使经过的蚂蚁聚集地大小之和最大,从而
召唤最多的蚂蚁。
【输入】
第1 行包含两个用空格隔开的整数n,m,意义见描述。
第2 到n+1 行,每行m 个字符(无间隔)且仅存在0 和1:同一偶数行中连
续x 个0 组成一个大小为x 的蚂蚁聚集地,1 为墙体;奇数行中0 表示蚁人可以从
此处通过。
【输出】
对于每组数据输出一个整数,表示经过路径中最大聚集地之和(不包含聚集
地之间的路径)。若蚁人无法到达最后一行则请输出“-1”。
4
【输入样例】
10 10
1111101111
1100001011
1101111111
1100000101
1110110111
1000110001
1101111011
1101000011
1101011111
1101010001
【输出样例】
17
【样例解释】

1111101111
1100001011
1101111111
1100000101
1110110111
1000110001
1101111011
1101000011
1101011111
1101010001
【数据规模】
对于20%的数据,n≤20,m≤20
对于50%的数据,n≤20,m≤100
对于100%的数据,n≤5000,m≤2000,保证n 是一个偶数,路径的数量不多于1×106

一开始想要建图,但是当时以为会超时,毕竟路径都有106那么多。然后大神告诉我们并不会超时,而且数据更大的时候只能建图了。见图可以不管重边,管了的话,反而要超时,索性不理。建完图后,拓扑排序加dp。我个人用的是递推,嗨呀,就是直接dp了,然而当时没有注意中间短路的情况,GG了10分。后来改了就对了。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#define MN 5005
#define MM 2005
using namespace std;
int n,m,mapp[MN][MM],f[MM],ans;
void inint()//just need dp like in the tree
{
	bool flag;
	for(int i=n;i>=1;i--)
	{
		flag=false;
		for(int j=1;j<=m;j++)
		{
			if(mapp[i][j]==0&&i%2==0)//the qiang is meaningless
			{
				int len=0,ma=-100;
				while(j+len<=m&&mapp[i][j+len]==0)
				{if(f[j+len]>ma) 
				ma=f[j+len];
				len++;}
				if(ma!=-1)
				for(int k=j;k<len+j;k++) f[k]=len+ma;
				j+=len;
			}
            if(mapp[i][j]==1) f[j]=-1;
		}
		for(int j=1;j<=m;j++)
		if(f[j]) flag=true;
	    if(flag==false) 
		{
			ans=-1; 
			return ;
		}
	}
		
}

int main()
{
	freopen("ant.in","r",stdin);
	freopen("ant.out","w",stdout);
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		getchar();
		for(int j=1;j<=m;j++)
		mapp[i][j]=getchar()-'0';
	}
		
    inint();
	for(int i=1;i<=m;i++)
	if(f[i]>ans) ans=f[i];
	if(ans==0) ans=-1;
	cout<<ans<<endl;
	return 0;
}

3. 计数
(amount. pas/c/cpp)
【题目描述】
我们都爱奎奎,最近奎奎给大家出了一道题。
他告诉了我们一个n*m 的矩阵点,在这个矩阵中的点可以连接成很多线,求
长度等于某一长度的线的条数。
【输入】)
第一行三个正整数n,m,t,第2-t+1 行为所求Wi。
【输出】
输出1 行,共t 个数,第i 个数为满足长度Wi 的条数。
【输入样例1】
3 3 1 例如此为3*3 的矩阵点
1
【输出样例1】
12
【输入样例2】
7 11 1
5
【输出样例2】
168
【输入样例3】
3 5 1
2
【输出样例3】
14
【数据说明】
测试点数据范围
1 2 N<=2000;M<=2000;T<=100
3 4 N<=1000000;M<=1000000;T<=100
5 6 N<=10000000;M<=10000000;T<=100
7 8 N<=100000000;M<=100000000;T<=100
9 10 N<=1000000000;M<=1000000000;T<=100
W<=2max(n,m);

题解:GG,考试的时候没有想出来正解,暴力还错了,因为没有注意到输出居然是一行!因为这道题算的是两个任意点之间的距离等于所求的距离。那么我们可以分为两个部分,一些是在坐标线上的,一些是不在坐标线上但是可以由勾股定理求得。前者很简单,simple这里就不说了。关键是后者枚举勾股数,而且我们晓得这个n和m都很大,直接枚举绝对GG。然后我是没有想出来的,嗨呀,太垃圾了。后来看题解,在那里推了半天,最后写出来还是GG,再一看,d与2*r/d弄混了。嗨呀,气。先把题解复制过来,红色是题解不清楚的地方:

因为x^2+y^2=r^2;

y=sqrt(r^2-x^2);

y=sqrt((r-x)*(r+x));

令d=gcd(r+x,r-x);

设A=(r-x)/d,B=(r+x)/d;

必然存在gcd(A,B)=1;

y^2=d^2*A*B;

A*B是完全平方数;

所以A是完全平方数,B是完全平方数;

设A=a*a,B=b*b;

显然a!=b;

令a<b;

所以a*a=(r-x)/d;

b*b=(r+x)/d;

两式相加得a*a+b*b=2r/d;所以说本来要枚举d从1-2r的,此处只用枚举到根号2r,来优化这个时间

1<d<sqrt(2r);

枚举d;

 此时d为2R的约数有两种情况:d=d或d=2R/d。这个地方千万不要弄混了,左边的d一直代表的是上面a*a+b*b=2r/d中的d=2r/d时,只不过是枚举另一个2r的因子,代入的时候还是带分母,不然就GG

         第一种情况:d=2r/d。枚举a∈[1,sqrt(2R/2d)] <由2*a*a < 2*r/d转变来>,算出对应的b=sqrt(2r/d-a^2),检查是否此时的A,B满足:A≠B且A,B互质 

         第二种情况:d=d。枚举a∈[1,sqrt(d/2)] <由2*a*a < d转变来>,算出对应的b=sqrt(d-a^2),检查是否此时的A,B满足:A≠B且A,B互质 

可以轻松求出x^2+y^2=r^2得整数解;

然后O(1)查询当前解的个数;

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #define ll long long
 6 using namespace std;
 7 int n,m,t;
 8 ll w;
 9 ll gcd_(ll x,ll y)
10 {
11     if(y==0) return x;
12     return gcd_(y,x%y);
13 }
14 void findnum(ll x)//double?
15 {
16     ll tims=0,nowt;
17     ll wid=0,hig=0;
18     if(x<=n) tims+=(n-x)*m;
19     if(x<=m) tims+=(m-x)*n;     
20     for(ll d=1;d*d<=2*x;d++)
21     if((2*x)%d==0)
22     {
23         for(ll a=1;a*a*2<=d;a++)
24         {
25             ll b=floor(sqrt(d-a*a));
26             if(b*b+a*a<d) continue ;
27             if(a==b) continue ;
28             if(gcd_(a,b)!=1) continue ;
29             wid=(b*b-a*a)*(2*x/d)/2,hig=(2*x/d)*a*b;
30             if(wid>=hig) continue ;
31             if(n>=wid&&m>=hig)
32             {
33             nowt=(n-wid)*(m-hig)*2;//from 1/4 part so it's twice
34             tims+=nowt;
35             }
36             if(n>=hig&&m>=wid)
37             {
38             swap(hig,wid);
39             nowt=(n-wid)*(m-hig)*2;
40             tims+=nowt;
41             }
42         }
43         for(ll a=1;a*a*d<=x;a++)
44         {
45             ll b=floor(sqrt(2*x/d-a*a));
46             if(b*b+a*a<(2*x/d)) continue ;
47             if(a==b) continue ;
48             if(gcd_(a,b)!=1) continue ;
49             wid=(b*b-a*a)*d/2,hig=d*a*b;
50             if(wid>=hig) continue ;
51             if(n>=wid&&m>=hig)
52             {
53             nowt=(n-wid)*(m-hig)*2;//from 1/4 part so it's twice
54             tims+=nowt;
55             }
56             if(n>=hig&&m>=wid)
57             {
58             swap(hig,wid);
59             nowt=(n-wid)*(m-hig)*2;
60             tims+=nowt;
61             }
62         }
63     }
64     cout<<tims<<' ';
65 }
66 int main()
67 {
68     freopen("amount.in","r",stdin);
69     freopen("amount.out","w",stdout);
70     cin>>n>>m>>t;
71     while(t)
72     {
73         cin>>w;
74         findnum(w);
75         t--;
76     }
77     return 0;
78 }
原文地址:https://www.cnblogs.com/fisch/p/6024375.html