(一)boolean
- 【题目描述】:
输入一个布尔表达式,请你输出它的真假值。
比如:( V | V ) & F & ( F | V )
V 表示 true,F 表示 false,& 表示与,| 表示或,! 表示非。
上式的结果是 F
注:! 的优先级最高,& 次之,| 最低 - 【Sample Input】
!V | V & V & !F & (F | V ) & (!F | F | !V & V) - 【Sample Output】
- 【注】对于 60% 的数据,表达式总长度 ≤ 10^3;对于 100% 的数据,表达式总长度 ≤ 10^6
【题解】看到这题反应就是表达式求值,妥妥20分钟打个栈过了。听说许多god被多个连续!给坑了,我的做法想想不会出事。。。当然表达式求值用栈或者分治都是妥妥过的。
//开两个栈一个记值一个记符号,符号取优先级判断
#include <cstdio>
#include <cstring>
int l,t,top,z[1000005],c[1000005];
char s[1000005];
int main()
{
for (char ch;~scanf("%c",&ch);)
if (ch=='(' || ch=='!' || ch=='&' || ch=='|' || ch==')'
|| ch=='V' || ch=='F') s[++l]=ch;
s[0]='(';s[l+1]=')';l+=2;
for (int i=0;i<l;++i)
{
if (s[i]=='V' || s[i]=='F') z[++t]=(s[i]=='V');
else
{
int k=0;
if (s[i]=='(') k=0;
if (s[i]=='!') k=1;
if (s[i]=='&') k=2;
if (s[i]=='|') k=3;
if (s[i]==')') k=4;
for (;top && k>c[top];c[top--]=0)
{
if (!c[top]) break;
if (c[top]==1) z[t]=!z[t];
if (c[top]==2) z[t-1]&=z[t],--t;
if (c[top]==3) z[t-1]|=z[t],--t;
}
if (k==4) c[top--]=0;
else c[++top]=k;
}
}
if (z[1]) printf("V");
else printf("F");
return 0;
}
(二)xor
- 【题目描述】:
给出 n 个数 a 1 ..a n ,求 a i xor a j , (i不等于j) 的最大值 - 【Sample Input】(第一行一个数 n 接下一行 n 个数 a 1 ..a n)
4
3 6 7 7 - 【Sample Output】(一行一个数 ans, 表示 a i xor a j , (i不等于j) 的最大值)
5 - 【注】对于 30% 的数据,n ≤ 1000;对于另外 20% 的数据,数据保证最后的 ans 一定是 2^k−1;对于 70% 的数据,n ≤ 10^5 ,0 ≤ a i ≤ 10^7 ;对于 100% 的数据,n ≤ 10^5 ,0 ≤ a i ≤ 10^16 。
【题解】
{30%} n^2暴力妥妥的不说了 0 0
{50%} 暴力基础上特判枚举一下 ans=2^k−1 的特殊情况 0 0
{80%} 暴力随意YY,考试的时候脑抽没想到字典树,就随便乱打。贪心的想,较大数和较小数由于位数差多,其乘积为最大的可能性较大。所以我们枚举的时候优先将大的和小的匹配,开个clock看看时间如果不太够了就跳出循环。还可以开个变量记一下可能的最大值,如果达到就break。这样80分。
{100%} 字典树。(%%% qzqzgfy 当初是这位god教的Trie)首先将数都转成二进制,并建出一棵字典树。接着我们将所有的数扫描一遍。贪心知,数位从高往低扫描时,我们尽量在树上取与当前数的当前位不同的,使它亦或值为1,从而使答案尽可能大。扫一遍取最大值即为答案。二进制位数最多为54位,所以复杂度O(54*n);
#include <cstdio>
#include <iostream>
#define LL long long
LL ans,a[100005];
int n,tot,f[8000000][2];
int main()
{
scanf("%d\n",&n);
for (int i=1;i<=n;++i)
{
scanf("%lld",&a[i]);LL x;
for (int dep=0,j=55;j>=0;--j,dep=f[dep][x])
if (!f[dep][x=(a[i]>>j)&1]) f[dep][x]=++tot;
}
for (int i=1;i<=n;++i)
{
LL t=0,x;
for (int dep=0,j=55;j>=0;--j)
if (f[dep][(x=(a[i]>>j)&1)^1]) dep=f[dep][x^1],t|=1ll<<j;
else dep=f[dep][x];
ans=std::max(ans,t);
}
printf("%lld\n",ans);
return 0;
}
(三)minimum
【题目描述】:
给出一幅由 n 个点 m 条边构成的无向带权图。
其中有些点是黑点,另外点是白点。
现在每个白点都要与他距离最近的黑点通过最短路连接(如果有很多个,可以选取其中任意一个) , 我们想要使得花费的代价最小。请问这个最小代价是多少?
注意:最后选出的边保证每个白点到黑点的距离任然是最短距离。【Sample Input】(第一行两个整数 n,m;第二行 n 个整数,0 表示白点,1 表示黑点;接下来 m 行,每行三个整数 x,y,z,表示一条连接 x 和 y 点,权值为 z 的边。)
5 7
0 1 0 1 0
1 2 11
1 3 1
1 5 17
2 3 1
3 5 18
4 5 3
2 4 5- 【Sample Output】(如果无解,输出 impossible;否则,输出最小代价)
5 - 【注】对于 30% 的数据,1 ≤ n ≤ 10,1 ≤ m ≤ 20;对于 100% 的数据,1 ≤ n ≤ 10^5 ,1 ≤ m ≤ 2 × 10^5 ,1 ≤ z ≤ 10^9 。
【题解】三个半小时考试,前两题没好好搞都在搞这题最短路,然后文件名写错了QAQ
(”god救我呀!“)
{30%} 暴力水过;
{100%} 将所有黑点缩成一个点向白点跑最短路{spfa},因为这张图其实很稀疏,时间跑出来也挺快的。缩点是因为显然黑点之间的连边没有意义。接着,将白点扫一遍,如果存在白点到不了黑点,输出impossible;否则设d[i]为i点的最小代价(这个代价不包括其它白点为走到黑点已经选取的边权):
d[v]=min(d[u],e.val) {dis[u]+e.val==dis[v]}
也就是,如果点v能通过点u走到一个距离它最近的黑点,就比较更新最小值。
#include <cstdio>
#include <iostream>
#define inf 1000000000
#define LL long long
#define INF 1ll<<60
struct edge{ int to,nxt,s;}e[2000005];
int i,n,m,x,y,z,cnt,tot,fi[1000005],q[10000005],a[1000005],d[1000005];
LL ans,dis[1000005];bool bo[1000005];
void add(int u,int v,int w)
{
e[++cnt].to=v;e[cnt].s=w;
e[cnt].nxt=fi[u];fi[u]=cnt;
}
void spfa()
{
int h=1,t=1;
for (int i=2;i<=tot;++i) dis[i]=INF;
for (bo[q[1]=1]=true;h<=t;bo[q[h++]]=false)
for (int i=fi[q[h]];i;i=e[i].nxt)
if (dis[q[h]]+e[i].s<dis[e[i].to])
{
dis[e[i].to]=dis[q[h]]+e[i].s;
if (!bo[e[i].to]) bo[q[++t]=e[i].to]=true;
}
for (int i=2;i<=tot;++i) d[i]=inf;
for (int i=1;i<=tot;++i)
for (int j=fi[i];j;j=e[j].nxt)
if (dis[i]+e[j].s==dis[e[j].to])
d[e[j].to]=std::min(d[e[j].to],e[j].s);
}
int main()
{
scanf("%d%d\n",&n,&m);
tot=1;
for (int i=1;i<=n;++i)
{
int x;scanf("%d",&x);
if (!x) a[i]=++tot;
}
for (int i=1;i<=m;++i)
{
int u,v,w;scanf("%d%d%d\n",&u,&v,&w);
if (!a[u]) u=1;else u=a[u];
if (!a[v]) v=1;else v=a[v];
if (u==v) continue;
add(u,v,w);add(v,u,w);
}
spfa();
for (int i=2;i<=tot && ans!=-1;++i)
if (d[i]!=inf) ans+=d[i];
else ans=-1;
if (ans<0) printf("impossible");
else printf("%lld\n",ans);
return 0;
}
【题外话】
考完试,有个神奇的学弟不服老师的标解,出了个神奇的数据卡掉了标程,原来标程是老师的学生写的OoO,然后老师拿了两个大牛的程序最终跑过了。
【Input】
5 4
1 0 0 0 1
1 2 3
2 3 2
3 4 1
4 5 4
【Output】
8