模拟题
P1054 [NOIP2005 提高组] 等价表达式
如果我们计算表达式的每一项的系数,再逐一比较,难度较大。所以,我们可以将每个柿子带入10个数,算出10个结果。如果10个结果都相等,就认为两个柿子等价。
在计算一个有括号,加减乘幂运算的表达式时,如果直接求解的话,难度仍然较大。但是利用它的优先级来递归求解,可以简单很多。
具体来说,设我们当前要计算的柿子对应字符串的
#include<iostream>
#include<cstdio>
#include<string>
#define ll long long
using namespace std;
const ll mod=1e9+7;
string b[10005],a,tmp;ll n,ans[205][55],ans1[55];
ll f(ll x,ll y){
ll sum=x;x=1;
while(y){
if(y&1)
x=x*sum%mod;
sum=sum*sum%mod;
y>>=1;
}
return x;
}
ll work(string a,ll l,ll r,ll x){
ll val=0,minn=1e12,pos,cnt=0,p[55];
for(int i=0;i<=50;++i)
p[i]=1e12;
for(int i=r;i>=l;--i){
if(a[i]==')') val+=100;
if(a[i]=='(') val-=100;
if(a[i]=='^') p[i]=val+3,++cnt;
if(a[i]=='*') p[i]=val+2,++cnt;
if(a[i]=='+') p[i]=val+1,++cnt;
if(a[i]=='-') p[i]=val+1,++cnt;
if(minn>p[i])
minn=p[i],pos=i;
}
if(cnt==0){
for(int i=l;i<=r;++i)
if(a[i]=='a')
return x;
ll num=0;
for(int i=l;i<=r;++i)
if(a[i]>='0'&&a[i]<='9')
num=(num*10%mod+a[i]-'0')%mod;
return num;
}
else{
if(a[pos]=='^')
return f(work(a,l,pos-1,x),work(a,pos+1,r,x));
if(a[pos]=='*')
return work(a,l,pos-1,x)*work(a,pos+1,r,x)%mod;
if(a[pos]=='+')
return (work(a,l,pos-1,x)+work(a,pos+1,r,x))%mod;
if(a[pos]=='-')
return (work(a,l,pos-1,x)+mod-work(a,pos+1,r,x))%mod;
}
return 0;
}
int main(){
getline(cin,a);cin>>n;getline(cin,tmp);
for(int i=1;i<=n;++i)
getline(cin,b[i]);
for(int i=1;i<=10;++i)
ans1[i]=work(a,0,a.size()-1,i);
for(int i=1;i<=n;++i){
for(int j=1;j<=10;++j)
ans[i][j]=work(b[i],0,b[i].size()-1,j);
}
for(int i=1;i<=n;++i){
bool ok=1;
for(int j=1;j<=10;++j)
if(ans1[j]!=ans[i][j])
ok=0;
if(ok)
cout<<(char)('A'-1+i);
}
return 0;
}
P1039 [NOIP2003 提高组] 侦探推理
枚举每一个人并假定他是罪犯,再枚举日期,然后判断是否矛盾即可。
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<map>
using namespace std;
int n,m,p,s[105],is[105],t[105];string name[25],a[105][105],tmp;
bool ok[105],is_crime[105];
string d[10]={" ","Monday.","Tuesday.","Wednesday.","Thursday.","Friday.","Saturday.","Sunday."};
map <string,int> f;
bool judge(int talk,int x,int y,int z){
//talk:说话者,x:说话者认为他是或不是罪犯,y:假定的罪犯,z:是或不是罪犯
if((z==1&&x==y)||(z==0&&x!=y)){//这次talk说的是实话
if(t[talk]==0)//talk之前已经说过谎,不符题意
return 0;
t[talk]=1;
}
else{//这次talk说谎
if(t[talk]==1)//talk之前说实话,不符题意
return 0;
t[talk]=0;
}
if(z==t[talk]) is_crime[x]=1;//z
return 1;
}
bool judge2(int talk,int x,int y){
//talk:说话者,x:说话者认为的日期,y:假定的日期
if(x!=y){//这次talk说的是实话
if(t[talk]==1) return 0;//talk之前已经说过谎,不符题意
t[talk]=0;
}
else{//这次talk说谎
if(t[talk]==0) return 0;//talk之前说实话,不符题意
t[talk]=1;
}
return 1;
}
bool work(int crime,int date){
bool hav=0;
for(int i=1;i<=p;++i){
if(!ok[i])
continue;
hav=1;
int now=is[i];
//以下为5种情况
if(s[i]==3&&a[i][1]=="I"&&a[i][2]=="am"&&a[i][3]=="guilty."){
if(!judge(now,now,crime,1))
return 0;
}
else if(s[i]==4&&a[i][1]=="I"&&a[i][2]=="am"&&a[i][3]=="not"&&a[i][4]=="guilty."){
if(!judge(now,now,crime,0))
return 0;
}
else if(s[i]==3&&f[a[i][1]]>=1&&f[a[i][1]]<=m&&a[i][2]=="is"&&a[i][3]=="guilty."){
if(!judge(now,f[a[i][1]],crime,1))
return 0;
}
else if(s[i]==4&&f[a[i][1]]>=1&&f[a[i][1]]<=m&&a[i][2]=="is"&&a[i][3]=="not"&&a[i][4]=="guilty."){
if(!judge(now,f[a[i][1]],crime,0))
return 0;
}
else if(s[i]==3&&a[i][1]=="Today"&&a[i][2]=="is"){
int _get=0;
for(int j=1;j<=7;++j)
if(d[j]==a[i][3])
_get=j;
if(!_get)
continue;
if(!judge2(now,_get,date))
return 0;
}
}
if(!hav&&m>1){//所有人的话都不符合格式,且不止一个人,说明罪犯难以确定
cout<<"Cannot Determine\n";
return 1;
}
int sum=0,sum2=0;
for(int i=1;i<=m;++i){
if(t[i]==0) ++sum;
else if(t[i]==1)++sum2;
}
if(sum>n||m-sum2<n)//说谎的人数不符题意
return 0;
int tot=0,point=0;
for(int i=1;i<=m;++i){
int pp=f[name[i]];
if(is_crime[pp])
++tot,point=i;
}
if(tot>1)
cout<<"Cannot Determine\n";
else if(tot==1)
cout<<name[point]<<endl;
else
cout<<name[crime]<<endl;
return 1;
}
int main(){
cin>>m>>n>>p;
f["I"]=f["am"]=f["not"]=f["guilty."]=f["is"]=f["Today"]=114;
for(int i=1;i<=7;++i)
f[d[i]]=114;
for(int i=1;i<=m;++i)
cin>>name[i],f[name[i]]=i;
for(int i=1;i<=p;++i){
if(tmp=="")
cin>>tmp;
int now=f[tmp.substr(0,tmp.size()-1)];
ok[i]=1;is[i]=now;//ok[i]表示第i句话是否符合格式,is[i]表示第i句话的讲话者
while(cin>>tmp){
if(tmp[tmp.size()-1]==':')
break;
if(!f[tmp])
ok[i]=0;
a[i][++s[i]]=tmp;
}
}
for(int i=1;i<=m;++i)
for(int j=1;j<=7;++j){
for(int k=1;k<=m;++k)
t[k]=-1,is_crime[k]=0;//t[k]表示k是否说谎,is_crime[k]表示k是否是罪犯
if(work(i,j))
return 0;
}
cout<<"Impossible\n";
return 0;
}
P7913廊桥分配
首先有一个性质:当廊桥数量增加时,原本能停在廊桥的飞机仍然能停在廊桥。
所以只需要处理出停在每个廊桥的飞机的数量,再做一遍前缀和,就能得到有
如何处理:首先将所有飞机按照到达时间从小到大排序,然后开一个以离开时间为关键字的小根堆,一个以廊桥编号为关键字的小根堆。
第一个小根堆储存当前停在廊桥的飞机,第二个小根堆储存当前空闲的廊桥。
当一个新飞机到达时,将在它之前离开的飞机弹出,并将这些飞机所在的廊桥压入第二个堆。此时的飞机便停在第二个堆中编号最小的廊桥。
#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
int n,m1,m2,ans,sa[100005],sb[100005];
struct node{
int w,a;
friend bool operator < (node x,node y){
return x.w>y.w;
}
};priority_queue <node> q;
priority_queue <int,vector <int> ,greater <int> > q2;
struct num{
int l,r;
};num a[100005],b[100005];
bool cmp(num x,num y){
return x.l<y.l;
}
int main(){
scanf("%d%d%d",&n,&m1,&m2);
for(int i=1;i<=m1;++i)
scanf("%d%d",&a[i].l,&a[i].r);
for(int i=1;i<=m2;++i)
scanf("%d%d",&b[i].l,&b[i].r);
sort(a+1,a+m1+1,cmp);sort(b+1,b+m2+1,cmp);
for(int i=1;i<=n;++i)
q2.push(i);
for(int j=1;j<=m1;++j){
while(!q.empty()&&a[j].l>q.top().w){
q2.push(q.top().a);
q.pop();
}
if(q2.empty())
continue;
++sa[q2.top()];
q.push((node){a[j].r,q2.top()});
q2.pop();
}
while(!q.empty())
q.pop();
while(!q2.empty())
q2.pop();
for(int i=1;i<=n;++i)
q2.push(i);
for(int j=1;j<=m2;++j){
while(!q.empty()&&b[j].l>q.top().w){
q2.push(q.top().a);
q.pop();
}
if(q2.empty())
continue;
++sb[q2.top()];
q.push((node){b[j].r,q2.top()});
q2.pop();
}
for(int i=1;i<=n;++i)
sa[i]+=sa[i-1],sb[i]+=sb[i-1];
for(int i=0;i<=n;++i)
ans=max(ans,sa[i]+sb[n-i]);
printf("%d\n",ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】