10-18考试记
300分。开心。
1、咒语
【题目描述】
亮亮梦到自己来到了魔法城堡,但一扇巨大的石门阻拦了他通向城堡内的路。
正当他沮丧之际,突然发现门上有一处机关,机关上有一张很长的纸条。
亮亮拿起纸条的一端,只见上面写着打开机关的方法:“打开机关需要念动
符咒,咒语是一串长为 L 的由 0 和 1 组成的字符串。在这张长纸条上列了 n 个
长为 L 的字符串,正确的咒语即是在纷繁的 2^L 种字符串中,与这些纸条上的
字符串相异度之和最小,并且在满足这一条件下,0 的个数最多的字符串。两个
字符串的相异度定义为对应位置不相等的字符对的个数。如‘011’和‘001’的
相异度为 1,因为它们有且只有第二个位置上的字符不相等。”
亮亮拉起纸条,只觉得纸条似乎永远也拉不完。这上面有着数以万计的字符
串,而每一个字符串的长度也或百或千,以人力看来是无法得到正确的咒语。你
能帮帮他,让他得以进入魔法城堡,一窥其中的奥秘吗?
【输入格式】
第一行为一个数字 N 。
接下来的 N 行,每行为一个长为 L 的 01 字符串。数据保证 N 个字符串等长。
【输出格式】
只有一行,是一个长为 L 的字符串 S,即为正确的咒语。
记录每一位有多少个1就行了。
code:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int wx=3017;
inline int read(){
int sum=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0';ch=getchar();}
return sum*f;
}
char c[wx][wx];
int l[wx];
int n;
//l[i]表示i这一位有多少个1
//如果这一位的1个数多于0,那么这一位答案为1
//否则为0
//暴力打不出来。。。
//SB吧打啥暴力
int main(){
freopen("curse.in","r",stdin);
freopen("curse.out","w",stdout);
n=read();
for(int i=1;i<=n;i++)scanf("%s",c[i]+1);
int len=strlen(c[1]+1);
for(int i=1;i<=n;i++){
for(int j=1;j<=len;j++){
if(c[i][j]=='1')l[j]++;
}
}
for(int i=1;i<=len;i++){
if(l[i]<=(n-l[i]))printf("0");
else printf("1");
}
fclose(stdin);
fclose(stdout);
return 0;
}
2、神光
【题目描述】
亮亮成功地念出了咒语,石门缓缓地自动移开,一道道绚丽的神光从城堡内
激射而出。亮亮好奇而又兴奋地走入了城堡中,迎面有一座极长的魔法阵。
魔法阵可以看作一条直线,它被均匀地分成了 1 000 000 000 个位置,一个位
置可以看成是一个格子。有些位置上筑有法坛,一共 N 座。亮亮只有破了眼前
的魔法阵,才能继续前进,而欲破法阵,必须毁掉所有的法坛。
亮亮身前有两根法杖:一根颜色血红,能发红色神光,光芒可以笼罩连续 L
个位置,并摧毁这 L 个位置上所有的法坛,最多使用 R 次;另一根颜色碧绿,
能发绿色神光,光芒可以笼罩连续 2L 个位置,并摧毁这 2L 个位置上所有的法
坛,最多使用 G 次。
法杖的神奇之处在于,L 的值必须由亮亮事先设定好,并且一经设定,便无
法更改。亮亮需要在规定的次数下摧毁所有法坛,并且使得 L 最小。
【输入格式】
第一行三个整数 N, R, G。
第 i (2<=i<=n+1) 行一个整数Ai,表示第 i 座法坛的位置。
【输出格式】
只有一个整数,表示 L 的最小值。
发现数据里的线索 缩小一下DP就可以了。
这个DP的思路还是不错的。
code:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int wx=3017;
inline int read(){
int sum=0,f=1; char ch=getchar();
while(ch<='0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0';ch=getchar();}
return sum*f;
}
int pos[wx],f[wx][wx];
int rr[wx],gg[wx];
int n,R,G,ans;
//二分?
//这数据范围真TM神了
//不太对,R+G>N直接有解1完事。
//OK DP+二分吧
bool ok(int L){
memset(f,0,sizeof f);
memset(rr,0,sizeof rr);
memset(gg,0,sizeof gg);
rr[n+1]=n; gg[n+1]=n;
for(int i=1;i<=n;i++){
rr[i]=upper_bound(pos+1,pos+1+n,pos[i]+L-1)-pos-1;
gg[i]=upper_bound(pos+1,pos+1+n,pos[i]+L*2-1)-pos-1;
}
for(int i=0;i<=R;i++){
for(int j=0;j<=G;j++){
if(i)f[i][j]=max(f[i][j],rr[f[i-1][j]+1]);
if(j)f[i][j]=max(f[i][j],gg[f[i][j-1]+1]);
}
}
if(f[R][G]==n)return true;
return false;
}
int main(){
freopen("light.in","r",stdin);
freopen("light.out","w",stdout);
n=read();R=read();G=read();
for(int i=1;i<=n;i++)pos[i]=read();
if(R+G>n){
puts("1");
return 0;
}
sort(pos+1,pos+1+n);
int l=1; int r=pos[n]-pos[1]+1;
while(l<=r){
int mid=l+r>>1;
if(ok(mid))ans=mid,r=mid-1;
else l=mid+1;
}
printf("%d
",ans);
fclose(stdin);
fclose(stdout);
return 0;
}
/*
2zz3
2zz3
3zz3
1zz2
2zz2
3zz3
1zz1
2zz2
3zz3
1zz1
2zz2
3zz3
1zz2
2zz2
3zz3
*/
3、迷宫
【题目描述】
破了魔法阵后,亮亮进入了一座迷宫。这座迷宫叫做“梦境迷宫”,亮亮只
有走出这座迷宫,才能从睡梦中醒来。
梦境迷宫可以用无向图来表示。它共有 n 个点和 m 条双向道路,每条道路
都有边权,表示通过这条道路所需的时间,且每条道路可以多次经过。亮亮位于
一号点,而出口则是 n 号点。原本,亮亮该找到一条最短路,快速冲出迷宫,然
而,梦境迷宫的特殊之处在于,如果沿着最短路到达出口,亮亮就会永远陷入梦
境。因此,亮亮必须寻找一条次短路。次短路的长度须严格大于最短路(可以有
多条)的长度,同时又不大于所有除最短路外的道路的长度。
你的任务,就是编写一个程序,帮助亮亮找到通向出口的次短路。
【输入格式】
第一行有两个整数 n、m,表示迷宫内共有 n 个点,m 条边。
接下来 m 行,每行三个整数 x、y、z,表示结点 x 和 y 之间连有一条边权为
z 的无向边。
两边Dij,再枚举边就可以了。
code:
#include <iostream>
#include <cstdio>
#include <queue>
#define int long long
using namespace std;
const int wx=500177;
inline int read(){
int sum=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0'; ch=getchar();}
return sum*f;
}
int n,m,ans=0x7fffffff;
int num;
int head[wx],diss[wx],dist[wx],vis[wx];
struct e{
int nxt,to,dis;
}edge[wx*2];
void add(int from,int to,int dis){
edge[++num].nxt=head[from];
edge[num].to=to;
edge[num].dis=dis;
head[from]=num;
}
struct node{
int u,d;
friend bool operator < (const node & a,const node & b){
return a.d>b.d;
}
};
priority_queue<node > q;
void Dijs(){
for(int i=1;i<=n;i++)diss[i]=0x7fffffff,vis[i]=0;
q.push((node){1,0});diss[1]=0;
while(q.size()){
int u=q.top().u; q.pop();
if(vis[u])continue; vis[u]=1;
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(diss[v]>diss[u]+edge[i].dis){
diss[v]=diss[u]+edge[i].dis;
q.push((node){v,diss[v]});
}
}
}
}
void Dijt(){
for(int i=1;i<=n;i++)dist[i]=0x7fffffff,vis[i]=0;
q.push((node){n,0});dist[n]=0;
while(q.size()){
int u=q.top().u; q.pop();
if(vis[u])continue; vis[u]=1;
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(dist[v]>dist[u]+edge[i].dis){
dist[v]=dist[u]+edge[i].dis;
q.push((node){v,dist[v]});
}
}
}
}
void work(){
int beg=diss[n];
for(int u=1;u<=n;u++){
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
int tmp=diss[u]+dist[v]+edge[i].dis;
if(tmp>beg&&tmp<ans)ans=tmp;
}
}
}
//。。。T3是傻逼题
signed main(){
freopen("maze.in","r",stdin);
freopen("maze.out","w",stdout);
n=read(); m=read();
for(int i=1;i<=m;i++){
int x,y,z;
x=read(); y=read(); z=read();
add(x,y,z); add(y,x,z);
}
Dijs();
Dijt();
work();
printf("%lld
",ans);
fclose(stdin);
fclose(stdout);
return 0;
}
继续加油。