打的好菜
题目链接
A-Arithmetic Problems
题意:实现 计算表达式,注意这里的加减乘除换了个意思如下:
- 代表是乘
/代表是加
+代表是除
x代表是减。
两个单调栈就可以解决了。
由于这里没有括号,所以我用了另一种方法求表达式求值,双端队列
遇到乘、除就计算,遇到+ -就放着。最后从前面往后扫就可以了。
但是呢,这种方法不适用于有括号的情况,赛后百度有没有栈的做法,发现都好乱好乱,又复杂又乱,这么简单的东西还搞什么优先级出来,不愧是专家级别想出的算法,很严谨,但也很难写,不适合在竞赛中写。
然后分析我的方法是否可以改善,答案是可以的。我就判断 字符队列最后一个是不是‘-’ 符号,是的话就将当前的数变成负数,然后字符队列删掉'-',放一个'+' 就可以了。在num放入数字队列的时候加一个if就可以了。
括号怎么处理?遇到右括号,就疯狂的计算栈顶的数 直到遇到左括号就行了。
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ll long long
#define maxn 1005
#define inf 1e9
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
inline ll read()
{
ll x=0,w=1; char c=getchar();
while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();}
while(c<='9'&&c>='0') {x=(x<<1)+(x<<3)+c-'0'; c=getchar();}
return w==1?x:-x;
}
deque<double>num;
deque<char>op;
const double esp=1e-11;
string s;
int cal(char c){if('0'<=c&&c<='9') return 1;else return 0;}
int main()
{
getline(cin,s);
for(int i=0;i<s.size();++i){
if(s[i]==' ') continue;
if(cal(s[i])){
double now=0;
int j=i;
for(;j<s.size();++j){
if(s[j]==' ') continue;
if(cal(s[j])) now=now*10+s[j]-'0';
else break;
}
//printf("now:%f\n",now);
if(op.size()&&(op.back()=='*'||op.back()=='/')){
if(op.back()=='/'&&now==0){puts("Cannot be divided by 0");return 0;}
if(op.back()=='*') now=num.back()*now;
else now=num.back()/now;
num.pop_back();op.pop_back();
}
num.push_back(now);
i=j-1;
}
else op.push_back(s[i]);
}
double ans=num.front();num.pop_front();
while(op.size()){
if(op.front()=='+') ans=ans+num.front();
else ans=ans-num.front();
num.pop_front();op.pop_front();
}
printf("%.2f\n",ans);
}
/*
1-2-3-4
*/
B-Birthday Gift
题意:给你n组(xi,yi),现在你选两组出来,使得min(xi+yj,yi+xj) 最大。
做法:假设xi+yj<yi+xj => xi-yi<xj-yj,那么我们对xi-yi 从大到小排序后,从大到小枚举。
枚举到当前的(xi,yi) 由于排序后,所有的j<i 都满足:xi+yj<yi+xj xi 已知 yi 已知,那我们只需要最大的yj 就可以了,不用管xj
假设 xi+yj>yi+xj 其实后面的跟上面是一样的操作,只是下标变化了而已。
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ll long long
#define maxn 1005
#define inf 1e9
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
inline ll read()
{
ll x=0,w=1; char c=getchar();
while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();}
while(c<='9'&&c>='0') {x=(x<<1)+(x<<3)+c-'0'; c=getchar();}
return w==1?x:-x;
}
const int N=2e5+10;
struct node
{
ll u,v,w;
}a[N];
int n;
bool cmp(node a,node b)
{
return a.w>b.w;
}
int main()
{
n=read();
rep(i,1,n) a[i].u=read();
rep(i,1,n) {
a[i].v=read();
a[i].w=a[i].u-a[i].v;
}
sort(a+1,a+1+n,cmp);
int id=1;
ll mx=a[1].v;
ll ans=0;
for(int i=2;i<=n;++i){
ans=max(ans,min(a[i].u+a[id].v,a[id].u+a[i].v));
if(a[i].v>mx){
mx=a[i].v;
id=i;
}
}
printf("%d\n",ans);
}
D-Stay up Late and Wake up Early
题意:从某个幸运的时刻开始 每隔x分钟醒来一次,最后到h:m 恰好醒来。x、h、m已知,求最小的醒了次数,
幸运时刻就是 小时 或 分钟 中带有7的。
做法:简单的从h:m 往前递推模拟就可以呃了。
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ll long long
#define maxn 1005
#define inf 1e9
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
inline ll read()
{
ll x=0,w=1; char c=getchar();
while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();}
while(c<='9'&&c>='0') {x=(x<<1)+(x<<3)+c-'0'; c=getchar();}
return w==1?x:-x;
}
const int N=1e2+10;
char s[N];
int cal(int n,int m)
{
if(n%10==7) return 1;
if(n/10%10==7) return 1;
if(m%10==7) return 1;
if(m/10%10==7) return 1;
return 0;
}
int main()
{
int _=read();while(_--)
{
int x=read();
scanf("%s",s+1);
int h=(s[1]-'0')*10+s[2]-'0';
int m=(s[4]-'0')*10+s[5]-'0';
//printf("hh:%d m:%d\n",h,m);
int ans=0;
while(1)
{
if(cal(h,m)){
printf("%d %02d:%02d\n",ans,h,m);
break;
}
if(m>=x) m-=x;
else{
m+=60;
m-=x;
h--;
if(h<0) h=23;
}
//printf("h:%d m:%d\n",h,m);
ans++;
}
}
}
H-Words Interesting
题意:给你文本串s,n个子序列串t,
1、s每个字符至少使用一次,
2、t串中不能没有s串没有的,
3、t串中的顺序 是在s串的顺序
做法:大大大水题,看错题了,以为s串每个字符只能被用一次。
n又只有20 这不就是简单的水题了嘛,代码都不想写了,直接贴别人的代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ll long long
#define maxn 1005
#define inf 1e9
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=1e6+10,MM=2e7+10,mod=1e9+7;
int n,m;
char s[N],p[N];
int c[26],cc[26];
void solve(){
memset(c,0,sizeof (c));
memset(cc,0,sizeof (cc));
int x;
scanf("%s%d",s+1,&x);
int flag=1;
n=strlen(s+1);
for(int i=1;i<=n;i++)c[s[i]-'a']++;
for(int i=1;i<=x;i++){
scanf("%s",p+1);
int m=strlen(p+1);
int now=1;
for(int i=1;i<=m;i++)cc[p[i]-'a']++;
for(int i=1;i<=n;i++){
if(s[i]==p[now])now++;
}
if(now<=m) flag=0;
}
if(flag==0){
printf("No\n");return;
}
for(int i=0;i<26;i++){
if(c[i]>cc[i]){
printf("No\n");return;
}
if(c[i]==0&&cc[i]){
printf("No\n");return;
}
}
printf("Yes\n");
}
int main()
{
int _;cin>>_;while(_--)solve();
return 0;
}
/*
20
abecd 2
aec
bed
*/
L-Yet Another Bracket Sequence
题意:给你一堆左括号和右括号,每次修改一个位置 若是左括号修改为右括号,若是右括号,修改为左括号,问每次修改后是否是平衡的括号序列。
做法:cf原题,线段树维护动态括号序列。原题链接:链接
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5;
/*
sum 维护的是左右括号的个数 为零的时候说明 左右括号数量相等
mi值维护的是最小值,最小值越小,那么连续的未匹配的右括号越多))))当mi[1]!=0 那么就是不匹配的
因为又剩余的))
mx值维护的是最大值,最大值越大,那么连续的未匹配的左括号越多((((,
当整个括号序列是匹配的,那么mx[1]就是维护的答案( 嵌套的最大括号)
*/
int sum[maxn<<2],mi[maxn<<2],ma[maxn<<2],n,m;
char s[maxn];
void update(int o,int l,int r,int pos,int c)
{
if(l==r)
{
sum[o]=c;mi[o]=c;ma[o]=c;
return ;
}
int m=(l+r)>>1;
if(pos<=m) update(o<<1,l,m,pos,c);
else update(o<<1|1,m+1,r,pos,c);
sum[o]=sum[o<<1]+sum[o<<1|1];
//很妙的更新方程:类似于动态更新前缀和
//我一直以为认为前缀和无法用线段树动态更新,现在这个方程证明了是可以的
ma[o]=max(ma[o<<1],sum[o<<1]+ma[o<<1|1]);
mi[o]=min(mi[o<<1],sum[o<<1]+mi[o<<1|1]);
}
int main()
{
scanf("%d%d",&n,&m);
scanf("%s",s+1);
for(int i=1;i<=n;++i) {
if(s[i]=='(') update(1,1,n,i,1);
else update(1,1,n,i,-1);
}
while(m--)
{
int x;scanf("%d",&x);
if(s[x]=='('){
update(1,1,n,x,-1);
s[x]=')';
}
else{
update(1,1,n,x,1);
s[x]='(';
}
if (mi[1]!=0 ||sum[1]!=0) puts("No");
else puts("Yes");
}
return 0;
}
M-Yet Another Stones Game
题意:给你n个权值a[i] 两个人玩,Little Gyro 先手,每次每个人选n/2个数 并且同时去掉任意的值,谁最后无法移动就是输了,若 Little Gyro 赢,输出 Sad Little Gyro 否则输出 Happy Little Gyro
做法:简单分析必胜态必败态。假设n=4
(0,0,0,0)必败态
(0,0,1,1)必胜态
(1,1,1,1)必败态
(1,1,1,2)必败态
(1,1,2,2)必胜态
(2,2,2,2)必败态
(2,2,3,3)必胜态
(2,3,4,3)必胜态
由此可以猜测结论,当最小值个数超过n/2 个 先手必败,因为无论你先手选哪n/2 个数,你取多少,我就取另外n/2个数 且一样多的话 使得你依旧处于必败态。
那对于最小值个数小于n/2 个嘞?怎么操作才能必胜?这里的话我还没懂怎么才能必胜,靠上面的猜测盲交一发。A了。。ac is ok 希望能有大佬指正~
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ll long long
#define maxn 1005
#define inf 1e9
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=1e2;
int n,m;
int a[N];
void solve(){
cin>>n;
int ans=0,mi=1e9;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
mi=min(mi,a[i]);
}
for(int i=1;i<=n;i++){
if(mi<a[i])ans++;
}
if(ans>=n/2)printf("Happy Little Gyro\n");
else printf("Sad Little Gyro\n");
}
int main()
{
int _;cin>>_;while(_--) solve();
}
/*
*/
N-Yet Another Hanoi Problem
题意:汉诺塔问题,改动:每次不能直接从a柱 到达c 柱。
做法:之前寒假训练出过两次此类题,补过题应该知道普通的汉诺塔跟二进制 +1 +1 的变化有关,且答案也是 2^n-1
然而这里有改动,其实很简单,就是多了一位变化,那就是3进制下的变化,答案就是3^n-1
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ll long long
#define maxn 1005
#define inf 1e9
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const ll mod=1e9+7;
inline ll read()
{
ll x=0,w=1; char c=getchar();
while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();}
while(c<='9'&&c>='0') {x=(x<<1)+(x<<3)+c-'0'; c=getchar();}
return w==1?x:-x;
}
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
ll powmod(ll a,ll b) {ll res=1;a%=mod;
assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
const int N=1e6+10;
ll f[N];
int n;
int main()
{
f[0]=1;
rep(i,1,N-1){
f[i]=f[i-1]*3%mod;
}
int _=read();while(_--)
{
n=read();
printf("%d\n",f[n]-1);
}
}