头更大
这个9月完就要去集训搞NOIP了。。。
9月30天也就3次测试。。。为防万一我还是每次测试玩都写个总结。。
补进度来的,上周有点浪。
第一题苟住,第二题第三题GG
Function(100/100)
题目背景
SOURCE:NOIP2015-SHY-6
题目描述
对于一个整数,定义 f(x) 为他的每个数位的阶乘的乘积。例如 f(135)=1! * 3! * 5! = 720。给出一个数 a(可以包含前缀零),a 满足他的至少一个数位大于 1 。我们要求出最大的整数 x ,其中 x 不含 0 或 1 ,并且满足 f(a) = f(x)。
输入格式
第一行一个整数 n ,表示 a 的长度。
接下来一个整数 a 。
输出格式
一行一个整数 x 表示答案。
样例数据 1
输入 [复制]
4
1234
输出
33222
样例数据 2
输入 [复制]
2
03
输出
3
备注
【样例1说明】
1! * 2! * 3! * 4! = 3! * 3! * 2! * 2! * 2!
【样例2说明】
0! * 3! = 3!
【数据范围】
对 30% 的输入数据 :n≤2
对 100% 的输入数据 :n≤15
暴力枚举多想即可。
MY/STD.CPP
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<string>
#include<algorithm>
#include<queue>
using namespace std;
int n,stk[60];
long long hh;
int cnt = 0;
void get(int n)
{
switch(n)
{
case 2:
stk[++cnt]=2;
break;
case 3:
stk[++cnt]=3;
break;
case 4:
stk[++cnt]=2;stk[++cnt]=2;stk[++cnt]=3;
break;
case 5:
stk[++cnt]=5;
break;
case 6:
stk[++cnt]=3;stk[++cnt]=5;
break;
case 7:
stk[++cnt]=7;
break;
case 8:
stk[++cnt]=2;stk[++cnt]=2;stk[++cnt]=2;stk[++cnt]=7;
break;
case 9:
stk[++cnt]=2;stk[++cnt]=3;stk[++cnt]=3;stk[++cnt]=7;
break;
}
}
int main()
{
cin >> n;
cin >> hh;
while(hh)
{
int jud = hh%10;
if(jud!=0&&jud!=1)get(jud);
hh/=10;
}
sort(stk+1,stk+cnt+1);
for(int i=cnt;i>=1;i--)cout<<stk[i];
return 0;
}
Box
题目背景
SOURCE:NOIP2015-SHY-6
题目描述
有个桌子长 R 宽 C ,被分为 R*C 个小方格。其中,一些方格上有箱子,一些方格上有按钮,一些方格上有障碍物,一些方格上是空地。现在有个任务,需要把所有箱子推到这些按钮上面。箱子有个特征,只能推不能搬不能拉。现在需要用最少的步数把所有箱子推到按钮上。
当然,箱子和人都只能以格子为单位移动,不存在一部分在格内一部分在格外的情况;只能向四个方向推,箱子和推箱子的队员都不能穿越障碍物。推动的定义是,人的前进方向被箱子挡住,且箱子在顺着前进方向的下一格不是箱子或者障碍物,那么就可以推着箱子和箱子一起前进一步。
输入格式
输入第一行有两个整数 R,C(4<=R,C<=7),代表桌子的长和宽,接下来一共有 R 行,每行有 C 个字符。
字符的含义:
0:代表空地
1:代表障碍物
2:代表箱子
3:代表按钮
4:人所在的初始地方
输入数据保证障碍物环绕整个地图,箱子数目跟按钮数目相同,箱子最少有一个,不会超过 3 个,队员肯定只有一个。不用考虑箱子初始就按着按钮的情况。保证有解。
输出格式
输出只有一行,为解决机关的最小步数。
样例数据 1
输入 [复制]
4 5
11111
14231
10231
11111
输出
4
备注
【样例说明】
在样例中,最快的方法之一是先向东把第一个箱子推到按钮上,然后向西走回原处,之后向南一步,再向东推第二个箱子到按钮上。至此任务完成,共使用了 4 步。
【数据范围】
对 30% 的输入数据 :箱子只有一个。
对 100% 的输入数据 :4<=R,C<=7。
一开始我怎么也觉得不可能用Dp应该用搜索才可能搞定像推箱子这样的题。。后来发现我错的离谱。。Dp大法好。。
虽然我到现在都还没看怎么懂orz。
STD.CPP
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<ctime>
#include<cctype>
#include<queue>
using namespace std;
int D[5][3],len,a[4],R[64][3],v[4],tot,n,m,A[8][8],f[50][50][50][50],pos[7][7],c[6000001][4];
bool b[9][9];
char sl[9];
int main()
{
//freopen("box.in","r",stdin);
//freopen("box.out","w",stdout);
cin>>n>>m;
int sx,sy;
D[1][1]=1;
D[1][2]=0;
D[2][1]=-1;
D[2][2]=0;
D[3][1]=0;
D[3][2]=1;
D[4][1]=0;
D[4][2]=-1;
len=0;
tot=0;
int cnt=0;
memset(R,0,sizeof(R));
memset(a,0,sizeof(a));
memset(v,0,sizeof(v));
for(int i=1;i<=n;i++)
{
scanf("%s",sl);
for(int j=1;j<=m;j++)
{
pos[i][j]=++cnt;
R[cnt][1]=i;
R[cnt][2]=j;
A[i][j]=sl[j-1]-'0';
if(A[i][j]==4) sx=i,sy=j,A[i][j]=0;
if(A[i][j]==2) a[++len]=pos[i][j];
if(A[i][j]==3) v[++tot]=pos[i][j];
}
}
memset(f,255,sizeof(f));
f[pos[sx][sy]][a[1]][a[2]][a[3]]=0;
c[1][0]=pos[sx][sy];
c[1][1]=a[1];
c[1][2]=a[2];
c[1][3]=a[3];
memset(b,true,sizeof(b));
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(A[i][j]==1) b[i][j]=false;
for(int k=1,l=1;l<=k;l++)
{
int ren=c[l][0],xiang1=c[l][1],xiang2=c[l][2],xiang3=c[l][3],xren=R[ren][1],yren=R[ren][2],x1=R[xiang1][1],y1=R[xiang1][2];
int x2=R[xiang2][1],y2=R[xiang2][2],x3=R[xiang3][1],y3=R[xiang3][2];
b[x1][y1]=false;
b[x2][y2]=false;
b[x3][y3]=false;
int ssx=f[ren][xiang1][xiang2][xiang3];
if(xiang1==v[1]&&xiang2==v[2]&&xiang3==v[3])
{
cout<<f[ren][xiang1][xiang2][xiang3];
return 0;
}
for(int i=1;i<=4;i++)
if(1<=xren+D[i][1]&&xren+D[i][1]<=n&&1<=yren+D[i][2]&&yren+D[i][2]<=m)
{
if(b[xren+D[i][1]][yren+D[i][2]]&&f[pos[xren+D[i][1]][yren+D[i][2]]][xiang1][xiang2][xiang3]==-1)
{
f[pos[xren+D[i][1]][yren+D[i][2]]][xiang1][xiang2][xiang3]=ssx+1;
c[++k][0]=pos[xren+D[i][1]][yren+D[i][2]];
c[k][1]=xiang1;
c[k][2]=xiang2;
c[k][3]=xiang3;
}
int q[4];
q[1]=xiang1;
q[2]=xiang2;
q[3]=xiang3;
if(pos[xren+D[i][1]][yren+D[i][2]]==q[2])swap(q[1],q[2]);
if(pos[xren+D[i][1]][yren+D[i][2]]==q[3])swap(q[1],q[3]);
if(pos[xren+D[i][1]][yren+D[i][2]]==q[1])
if(1<=xren+2*D[i][1]&&xren+2*D[i][1]<=n&&1<=yren+2*D[i][2]&&yren+2*D[i][2]<=m&&b[xren+2*D[i][1]][yren+2*D[i][2]])
{
q[1]=pos[xren+2*D[i][1]][yren+2*D[i][2]];
for(int j=1;j<=3;j++)
for(int k=j+1;k<=3;k++)
if(q[k]!=0&&q[k]<q[j]) swap(q[j],q[k]);
if(f[pos[xren+D[i][1]][yren+D[i][2]]][q[1]][q[2]][q[3]]==-1)
{
f[pos[xren+D[i][1]][yren+D[i][2]]][q[1]][q[2]][q[3]]=ssx+1;
c[++k][0]=pos[xren+D[i][1]][yren+D[i][2]];
c[k][1]=q[1];
c[k][2]=q[2];
c[k][3]=q[3];
}
}
}
b[x1][y1]=true;
b[x2][y2]=true;
b[x3][x3]=true;
}
cout<<"17";
return 0;
}
Tree
题目背景
SOURCE:NOIP2015-SHY-6
题目描述
给你一个有 N 个点 M 条边的无向带权连通图,每条边是白色或黑色,求一颗最小权的恰好有 K 条白边的生成树。
输入格式
第一行三个数 N、M、K ,分别表示点数、边数和所需的白边数。
接下来 M 行,每行四个数 u、v、w、c ,分别表示一条边的两个端点(从0开始标号)、边权和颜色(0表示白色,1表示黑色)。
输入数据保证有解。
输出格式
一行一个数表示所求生成树的边权和。
样例数据 1
输入 [复制]
2 2 1
0 1 1 1
0 1 2 0
输出
2
备注
【数据范围】
对 20% 的输入数据 :1≤N≤15。
对 100% 的输入数据 :1≤N≤50000,1≤M≤100000, 1≤w≤100。
貌似听大神讲过的一道原题。。。然而下来好像没懂就没管了。
论学一样懂一样的重要性。
二分大法好orz。
STD.CPP
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
int n,m,k,a,b,d,e,l,r=0,mid,cnt,cntt;
int fa[50005];
long long sum;
struct node {
int u,v,w,c;
}edge[100005],bian[100005];
bool cmp(node a,node b)
{
if(a.w==b.w) return a.c<b.c;
return a.w<b.w;
}
int getfa(int x)
{
if(fa[x]==x) return x;
fa[x]=getfa(fa[x]);
return fa[x];
}
inline bool check(int mid) {
for(int i=1;i<=m;++i)
{
bian[i]=edge[i];
if(!edge[i].c) bian[i].w = edge[i].w + mid;
}
cnt=0,cntt=0,sum=0;
for(int i=0;i<n;++i) fa[i]=i;
sort(bian+1,bian+m+1,cmp);
for(int i=1;i<=m;++i)
{
a=getfa(bian[i].u);
b=getfa(bian[i].v);
if(a!=b) {
fa[a] = b;
cnt++;
if(!bian[i].c) {
cntt++;
sum += bian[i].w;
}
else sum+=bian[i].w;
if(cnt==n-1) break;
}
}
return (cntt >= k);
}
int main()
{
cin>>n>>m>>k;
for(int i=1;i<=m;++i)
{
cin>>a>>b>>d>>e;
edge[i].u=a;
edge[i].v=b;
edge[i].w=d;
edge[i].c=e;
}
r=150; l=-r;
while (l+1<r)
{
mid=(l+r)/2;
if (check(mid)) l=mid;
else r=mid;
}
check(l);cout << sum-k*l;
return 0;
}
感想
T1现在能(变)苟(简)住(单)了。。T2,T3的暴力还要学学,打得好暴力,定能出奇迹
还有要补补二分和Dp了。。