莫尼塞垫底祭。。两个号大凶果然没有好事情
绍兴一中NOI P模拟赛小小小小题解
1.脱离地牢
Description
在一个神秘的国度里,年轻的王子Paris与美丽的公主Helen在一起过着幸福的生活。他们都随身带有一块带磁性的阴阳魔法石,身居地狱的魔王Satan早就想着得到这两块石头了,只要把它们溶化,Satan就能吸收其精华大增自己的魔力。于是有一天他趁二人不留意,把他们带到了自己的地牢,分别困在了不同的地方。然后Satan念起了咒语,准备炼狱,界时二人都将葬身于这地牢里。 危险!Paris与Helen都知道了Satan的意图,他们要怎样才能打败魔王,脱离地牢呢?Paris想起了父王临终前给他的备忘本,原来他早已料到了Satan的野心,他告诉Paris只要把两块魔法石合在一起,念出咒语,它们便会放出无限的光荣,杀死魔王,脱离地牢,而且本子上还附下了地牢的地图,Paris从中了解到了Helen的位置所在。于是他决定首先要找到Helen,但是他发现这个地牢很奇怪,它会增强二人魔法石所带的磁力大小,而且会改变磁力的方向。这就是说,每当Paris向南走一步,Helen有可能会被石头吸引向北走一步。而这个地狱布满了岩石与熔浆,Paris必须十分小心,不仅他不能走到岩石或熔浆上,而且由于他行走一步,Helen的位置也会改变,如果Helen碰到岩石上,那么她将停留在原地,但如果Helen移动到了熔浆上,那么她将死去,Paris就找不到她了。 Paris仔细分析了地图,他找出了一条最快的行走方案,最终与Helen相聚。他们一起念出了咒语“·#¥%^…*&@!”,轰隆一声,地牢塌陷了,他们又重见光明…
Input
输入数据第一行为两个整数n,m(3<=n,m<=20),表示地牢的大小,n行m列。接下来n行,每行m个字符,描述了cf地牢的地图,“.”代表通路,“#”代表岩石,“!”代表熔浆,“H”表示Helen,“P”表示Paris。输入保证地牢是封闭的,即四周均是岩石或熔浆。接下来一行有四个字符“N”(北),“S”(南),“W”(西),“E”(东)的排列,表示Paris分别向NSWE四个方向走时Helen受磁石磁力影响的移动方向。
Output
输出文件只有一行,如果Paris能找到Helen,输出一整数d,为Paris最少需要行走的步数;如果Paris在255步之后仍找不到Helen,则输出“Impossible”。注意相遇是指Paris与Helen最终到达同一个格子,或者二人在相邻两格移动后碰到了一起,而后者的步数算他们移动后的步数。
Sample Input
5 5
#####
#H..#
#.!.#
#.#P#
#####
WNSE
Sample Output
5
这道题的相遇条件是走到同一个格子或者两人互换位置。然后就是妥妥的bfs,记得vis数组去重放在统计答案之后。不然会wa两个点。
另.蒟蒻还目睹了yyh用dfs水掉了此题。。。然而跑的飞快
#include
#include
#include
#include
using namespace std;
int n,m,flag,ans=256,fh[5];
char c[200][200];
int f[21][21][21][21];
int dx[5]={-1,1,0,0};
int dy[5]={0,0,-1,1};
void dfs(int sx,int sy,int tx,int ty,int step)
{
if(f[sx][sy][tx][ty]<=step||step>=256||step>=ans) return;
f[sx][sy][tx][ty]=step;//根据yyh大佬改进的判重
if((sx==tx&&sy==ty))
{
ans=step;
flag=1;
return;
}
if((sx==tx&&abs(sy-ty)==1)||(abs(sx-tx)==1&&sy==ty)){
for(int i=0;i<4;i++){
if(sx+dx[i]==tx&&sy+dy[i]==ty&&tx+dx[fh[i]]==sx&&ty+dy[fh[i]]==sy){
ans=step+1;
flag=1;
return;
}
}
}
if(ans<=step) return;
// cout<>ch;
if(ch=='N') fh[i]=0;
else if(ch=='S') fh[i]=1;
else if(ch=='W') fh[i]=2;
else if(ch=='E') fh[i]=3;
}
memset(f,0x3f3f3f3f,sizeof f);
// for(int i=0;i<4;i++)
// cout<
2.Reward
题目描述:
众所周知,liverpool的主帅贝尼特斯喜欢轮换阵法,是阵法变换的大家。他的首发阵容往往让对方主帅无法捉摸,以至于失去布阵的先机,其创下的999场首发阵容不同的纪录至今无人能望其项背。其接班人dick充分继承了他的优良传统,并将其发扬光大,出现了完全随机的阵容……
为什么dick可以毫无障碍的把轮换进行到底呢?其原因在于dick的一个黑箱小程序,他的功用在于给定一个数n,可求出约数总数为n的最小数——根据这个数字,dick再经过一系列的数学式转换,最终可以获得11个首发球员的号码。
作为liverpool竞争对手的Manchester Unit、Arsenal、Chelsea联合起来,经过多年的潜访调查考证研究分析证明后终于成功的盗得了dick的输入数n的规律,以及最后转化的数学式,眼看成功胜利在望,他们开出巨额赏金悬赏可以解决dick黑箱小程序的人才,以实现他们打破liverpool不败神话的愿望。
不管为了巨额奖金还是击败liverpool的荣誉,我想你应该会试一试吧。
输入数据:
输入仅一个数n,表示约数总数。
输出数据:
输出仅一个数,表示最小的具有n个约数的数。
输入样例:
4
输出样例:
6
数据规模:
对于50%的数据 n<=50
对于100%的数据 n<=50000
公式:原数=p1(t1)*p2(t2)p3^(t3)....
约数个数=(t1+1)(t2+1)(t3+1)(t4+1)...
45分到手。
然后我们考虑DP
Mst数组表示用第i个素数之前有j个因数,用后还剩下需要消除的因数个数
f数组表示第i个素数用后使得剩下j个因数所需的答案log10之后的数
关于为什么要log10:因为约数定理是乘法,而乘法会比较麻烦,所以转成位数后用加法实现,这也是为什么lg和from数组要用double的原因
#include
#define maxn 50010
#define int long long
#define mo 1000000000
using namespace std;
int zhi[20]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53},n,mst[20][maxn];
double lg[20],f[20][maxn];
struct bignum
{
int a[2300];
bignum(int i=0)
{
memset(a,0,sizeof a);
if(!i) return;
a[0]=1;
a[1]=i;
}
friend bignum operator *(bignum x,bignum y)
{
bignum z;
for(int i=1;i<=x.a[0];i++)
{
int p=0;
for(int j=1;j<=y.a[0];j++)
{
p+=x.a[i]*y.a[j]+z.a[i+j-1];
z.a[i+j-1]=p%mo;
p/=mo;
}
z.a[i+y.a[0]]=p;
}
z.a[0]=x.a[0]+y.a[0];
while(z.a[0]&&!z.a[z.a[0]])
z.a[0]--;
return z;
}
void print()
{
printf("%lld",a[a[0]]);
for(int i=a[0]-1;i>0;i--)
printf("%09lld",a[i]);
puts("");
}
};//高精
bignum power(int x,int y)
{
bignum s=bignum(1),p=bignum(x);
if(y==0) return s;
for(;y;y/=2,p=p*p)
if(y&1) s=s*p;
return s;
}
void work(int i,int j,int k)
{
if(f[i][k]<=f[i-1][j]+(j/k-1)*lg[i]) return;
mst[i][k]=j;
// wrs(mst[i][k]);
f[i][k]=f[i-1][j]+(j/k-1)*lg[i];
}
signed main()
{
freopen("reward.in","r",stdin);
freopen("reward.out","w",stdout);
for(int i=1;i<17;i++)
lg[i]=log10(zhi[i]);
// for(int i=1;i<17;i++)
// printf("%lf ",lg[i]);
scanf("%d",&n);
if(n==1)
{
puts("1");
return 0;
}
for(int i=0;i<=16;i++)
for(int j=1;j<=n;j++)
f[i][j]=1e15;
f[0][n]=1;
for(int i=1;i<17;i++)
for(int j=1;j<=n;j++)
{
if(n%j) continue;
int k=1;
for(;k*k
3.书本整理 4.木棍 输入: 输出: 样例输入1 样例输出1 样例输入2 样例输出2 贪心。按长度排序,按宽度求lis,标记,继续求lis,直到全部标记完毕。做过的题目思路有影响然而写挂了?!以后还是要好好总结
【问题描述】
小明的书架上放了许多书,为了使书架变得整洁,小明决定整理书架,他将所有书按高度大小排列,这样排了之后虽然整齐了许多,但小明发现,书本的宽度不同,导致书架看上去还是有些凌乱。小明把这个凌乱值定义为相邻两本书的宽度差的绝对值的和。
例如有4本书:
1×2
5×3
2×4
3×l
那么小明将其排列整齐后的顺序是:
1×2
2×4
3×l
5x3
凌乱值就是2+3+2=7。
于是小明决定拿掉其中的k本书,使凌乱值最小,你能帮他求出这个最小值吗?已知每本书的高度都不一样。
【问题输入】
第一行两个数字n和k,代表书总共有n本,要求从中去掉k本。(l≤n≤100,1≤k
一行一个整数,表示书架的最小凌乱值。
【样例输入】
4 1
1 2
2 4
3 1
5 3
【样例输出】
3
【数据范围】
30%的数据,n≤20。
100%的数据,n≤l00.k求n本书去掉k本的最小凌乱值。
f[i][j]表示前i本书去除j本书,第i本必须留下所获得的最小代价
[伪代码]
for(int kk=0;kk<=min(k,i-2);kk++)
f[i][j]=min(f[i][j],f[i-kk-1][j-kk]+abs(a[i].w-a[i-kk-1].w));
if(j==i-1) f[i][j]=0;
ans=min(f[n-i][k-i])(0<=i<=k)
或者反过来更好理解:求n本书取出 n-k本最小凌乱值。
f[i][j]表示前i本书取j本书,第i本必须留下所获得的最小代价
for(int i=1;i<=n;i++){
f[i][1]=0;
for(int j=2;j<=min(i,n-k);j++)
for(int l=1;l
有N根木棍,每根的长度L和重量W已知。这些木棍将被一台机器一根一根地加工。机器需要一些启动时间来做准备工作,启动时间与木棍被加工的具体情况有关。启动时间遵循以下规则:
1.加工第一根木棍的启动时间为1分钟。
2.加工完长度为Li,重量为Wi的木棍后,紧跟着加工长度为Li+1,重量为
Wi+1的木棍时,若Li<=Li+1且Wi<=Wi+1,则加工木棍I+1时,不需要启动时间。例如:有5根木棍,它们的长度和重量为(9,4),(2,5),(1,2,),(5,3),(4,1),则最小总启动时间为2分钟(加工序列为(4,1),(5,3),(9,4),(1,2),(2,5))。
第一行一个整数n(1<=n<=5000),表示木棍的数量。第二行2n个整数,l1,w1,l2,w2,…,ln,wn(1<=li,wi<=10000),为各根木棍的长度和重量,这2n个整数以若干个空格分隔。
一行: 一个整数,即最小总启动时间。
5
4 9 5 2 2 1 3 5 1 4
2
3
2 2 1 1 2 2
1
既然写了那么多遍代码就不给了