我的博客园传送门,看起来更方便一些
思路:题目问有牌子就行,那就贪心,当懒狗摸铜牌最优。
但是有一点要注意。不能直接当前rank/0.6向上取整来算。因为银牌和铜牌是由金牌 * 2和 * 3得到的。比如rank = 5时,若直接 ⌈ 5 / 0.6 ⌉ \lceil 5/0.6 \rceil ⌈5/0.6⌉会得到9,然而这个时候是没有金牌的(9*0.1=0,向下取整)。
所以这个题要先将当前 ⌈ r a n k / 6 ⌉ \lceil rank/6 \rceil ⌈rank/6⌉得到当前rank为铜牌时金牌应该是在什么位置,然后用这个位置乘10即是最小人数。对于当前rank为银牌和金牌也是同样判断。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define FAST ios::sync_with_stdio(false)
#define abs(a) ((a)>=0?(a):-(a))
#define sz(x) ((int)(x).size())
#define all(x) (x).begin(),(x).end()
#define mem(a,b) memset(a,b,sizeof(a))
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define rep(i,a,n) for(int i=a;i<=n;++i)
#define per(i,n,a) for(int i=n;i>=a;--i)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<ll,ll> PII;
const int maxn = 1e5+200;
const int inf=0x3f3f3f3f;
const double eps = 1e-7;
const double pi=acos(-1.0);
const int mod = 1e9+7;
inline int lowbit(int x){
return x&(-x);}
ll gcd(ll a,ll b){
return b?gcd(b,a%b):a;}
void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y){
if(!b){
d=a,x=1,y=0;}else{
ex_gcd(b,a%b,d,y,x);y-=x*(a/b);}}//x=(x%(b/d)+(b/d))%(b/d);
inline ll qpow(ll a,ll b,ll MOD=mod){
ll res=1;a%=MOD;while(b>0){
if(b&1)res=res*a%MOD;a=a*a%MOD;b>>=1;}return res;}
inline ll inv(ll x,ll p){
return qpow(x,p-2,p);}
inline ll Jos(ll n,ll k,ll s=1){
ll res=0;rep(i,1,n+1) res=(res+k)%i;return (res+s)%n;}
inline ll read(){
ll f = 1; ll x = 0;char ch = getchar();while(ch>'9'||ch<'0') {
if(ch=='-') f=-1; ch = getchar();}while(ch>='0'&&ch<='9') x = (x<<3) + (x<<1) + ch - '0', ch = getchar();return x*f; }
int dir[4][2] = {
{
1,0}, {
-1,0},{
0,1},{
0,-1} };
int main()
{
int kase;
cin>>kase;
while(kase--)
{
ll n , rank, m;
cin>>n>>rank>>m;
if(!m) cout<<-1<<'\n';
else if(((rank+5)/6)*10<=n&&((rank+5)/6)*10>0) cout<<((rank+5)/6)*10<<'\n';
else if(((rank+2)/3)*10<=n&&((rank+2)/3)*10>0) cout<<((rank+2)/3)*10<<'\n';
else if(rank*10<=n) cout<<rank*10<<'\n';
else cout<<-1<<'\n';
}
return 0;
}
思路:既然大小写都可以随意变化,就无需考虑大小写了。我们统一小写看待。即是要拼凑模式串“hollow knight”字符串。
又知道可以将任意字符变成空格,那我们就直接将不是模式串里的字符全部变成空格,这样最优。
然后主体代码其实就可以直接暴力。用cur指针指向当前拼凑到哪个字符,如果非空格字符不够了就直接退出,若是空格不够,就从目前已有的字符里面给他一个(按照模式串顺序从前往后找)。然后拼凑完一整串就ans++,同时指针回到开始位置,如此往复直到不能再凑。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define FAST ios::sync_with_stdio(false)
#define abs(a) ((a)>=0?(a):-(a))
#define sz(x) ((int)(x).size())
#define all(x) (x).begin(),(x).end()
#define mem(a,b) memset(a,b,sizeof(a))
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define rep(i,a,n) for(int i=a;i<=n;++i)
#define per(i,n,a) for(int i=n;i>=a;--i)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<ll,ll> PII;
const int maxn = 1e5+200;
const int inf=0x3f3f3f3f;
const double eps = 1e-7;
const double pi=acos(-1.0);
const int mod = 1e9+7;
inline int lowbit(int x){
return x&(-x);}
ll gcd(ll a,ll b){
return b?gcd(b,a%b):a;}
void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y){
if(!b){
d=a,x=1,y=0;}else{
ex_gcd(b,a%b,d,y,x);y-=x*(a/b);}}//x=(x%(b/d)+(b/d))%(b/d);
inline ll qpow(ll a,ll b,ll MOD=mod){
ll res=1;a%=MOD;while(b>0){
if(b&1)res=res*a%MOD;a=a*a%MOD;b>>=1;}return res;}
inline ll inv(ll x,ll p){
return qpow(x,p-2,p);}
inline ll Jos(ll n,ll k,ll s=1){
ll res=0;rep(i,1,n+1) res=(res+k)%i;return (res+s)%n;}
inline ll read(){
ll f = 1; ll x = 0;char ch = getchar();while(ch>'9'||ch<'0') {
if(ch=='-') f=-1; ch = getchar();}while(ch>='0'&&ch<='9') x = (x<<3) + (x<<1) + ch - '0', ch = getchar();return x*f; }
int dir[4][2] = {
{
1,0}, {
-1,0},{
0,1},{
0,-1} };
int cnt[600];
string pattern = "hollow knight";
int Map[600];
int main()
{
FAST;
cin.tie(0), cout.tie(0);
rep(i,0,pattern.size()-1) Map[pattern[i]] = 1;
int kase;
cin>>kase;
while(kase--)
{
int n; mem(cnt,0);
cin>>n;
string s;
rep(i,1,n)
{
string tmp; cin>>tmp;
s += tmp;
}
rep(i,0,s.size()-1)
{
if(Map[s[i]]) cnt[s[i]]++;
else if(s[i]>='A'&&s[i]<='Z'&&Map[s[i]+32]) cnt[s[i]+32] ++;
else cnt[' ']++;
}
int ans = 0;
int cur = 0;
while(1)
{
int flag = 0;
if(cnt[pattern[cur]]) cnt[pattern[cur]]--, flag = 1;
else if(pattern[cur]==' ')
{
rep(i,0,pattern.size()-1) if(cnt[pattern[i]]) {
cnt[pattern[i]]--,flag=1;break;}
}
if(!flag) break;
if(cur==pattern.size()-1) ans++;
cur = (cur+1)%pattern.size();
}
cout<<ans<<endl;
}
return 0;
}
思路:标签是dfs我用dfs却超时。。。不过好在O( n 3 n^3 n3)的暴力也能过。这个题雷区比较多。
1.其中上手最容易碰到的坑就是想当然的把小的放在f[]项小的位置。这样会产生什么问题?如2 5 7 9,按照这个顺序,只能取到k=3。但是调换一个顺序5 2 7 9,这样又可以全部取到了,k=4。所以这个题要对前两位进行枚举。
2.0不能放在里面考虑,所以核心代码开始之前要预处理一下0的个数。
3.这样主要的步骤就是:三重循环,外面两层用来枚举f[1]和f[2],第三层循环用来构造以a[i],a[j]为开头的序列。然后每次更新最大值。为了优化代码,这一步之前要先排序,这样选好两个之后,就可以直接在这两个数后面挑了。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define FAST ios::sync_with_stdio(false)
#define abs(a) ((a)>=0?(a):-(a))
#define sz(x) ((int)(x).size())
#define all(x) (x).begin(),(x).end()
#define mem(a,b) memset(a,b,sizeof(a))
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define rep(i,a,n) for(int i=a;i<=n;++i)
#define per(i,n,a) for(int i=n;i>=a;--i)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int maxn = 1e5+200;
const int inf=0x3f3f3f3f;
const double eps = 1e-7;
const double pi=acos(-1.0);
const int mod = 1e9+7;
inline int lowbit(int x){
return x&(-x);}
ll gcd(ll a,ll b){
return b?gcd(b,a%b):a;}
void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y){
if(!b){
d=a,x=1,y=0;}else{
ex_gcd(b,a%b,d,y,x);y-=x*(a/b);}}//x=(x%(b/d)+(b/d))%(b/d);
inline ll qpow(ll a,ll b,ll MOD=mod){
ll res=1;a%=MOD;while(b>0){
if(b&1)res=res*a%MOD;a=a*a%MOD;b>>=1;}return res;}
inline ll inv(ll x,ll p){
return qpow(x,p-2,p);}
inline ll Jos(ll n,ll k,ll s=1){
ll res=0;rep(i,1,n+1) res=(res+k)%i;return (res+s)%n;}
inline int read(){
int f = 1; int x = 0;char ch = getchar();while(ch>'9'||ch<'0') {
if(ch=='-') f=-1; ch = getchar();}while(ch>='0'&&ch<='9') x = (x<<3) + (x<<1) + ch - '0', ch = getchar();return x*f; }
int dir[4][2] = {
{
1,0}, {
-1,0},{
0,1},{
0,-1} };
int a[500];
int n;
int ans = 0;
int cur = 2;
int main()
{
// FAST;
// cin.tie(0), cout.tie(0);
int kase;
scanf("%d",&kase);
while(kase--)
{
scanf("%d",&n);
ans = 0; cur = 2;
int cnt = 0;
rep(i,1,n) a[i] = read(),cnt += (a[i]!=0);
if(cnt<=2)
{
printf("%d\n",cnt);
continue;
}
sort(a+1,a+1+n); //排序完
rep(i,1,n) rep(j,1,n) //外两层循环控制开始两个位置
{
if(a[i]&&a[j]&&i!=j) //不能为0且不是同一个位置
{
int pre = a[i]; //用pre代表f[i-1], ppre代表f[i-2]
int ppre = a[j];
cur = 2; //那么初始步数是2
rep(k,max(i,j),n) //因为排序好了,那f[3]就从i,j中的最大值开始遍历(前面的肯定不够大嘛)
{
if(pre + ppre>a[n]) break; //剪枝
if(pre + ppre== a[k]) ppre = pre, pre = a[k],cur++; //诶发现相等了,交换一下ppre, pre,同时计数++。
}
ans = max(ans,cur); //比较。
}
}
printf("%d\n",ans);
}
return 0;
}
思路:可能很多人被题面吓到了,其实这个题暴力整一整就好了。
1.我们把这n+m+1个操作看成n+m+1个指令。我们要能发现的是,为了保证步数最小,每个指令最多也就用一次。为什么?你用偶数次的话不是又变回来了呀~。
2.确定了每个指令只能用一次,那么问题就变成了这n+m+1个指令选或不选的问题。这不就是裸的回溯问题嘛:
当前指令选,那么将这个指令代表的位置置换一下,递归进入下一个指令。
若当前指令不选,就啥也不干进入下一个指令。
递归出口就是指令用完了或者全置为1了。选指令的时候存一下记录,每次搞到全1就比较一下即可。详见代码。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define FAST ios::sync_with_stdio(false)
#define abs(a) ((a)>=0?(a):-(a))
#define sz(x) ((int)(x).size())
#define all(x) (x).begin(),(x).end()
#define mem(a,b) memset(a,b,sizeof(a))
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define rep(i,a,n) for(int i=a;i<=n;++i)
#define per(i,n,a) for(int i=n;i>=a;--i)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<ll,ll> PII;
const int maxn = 1e5+200;
const int inf=0x3f3f3f3f;
const double eps = 1e-7;
const double pi=acos(-1.0);
const int mod = 1e9+7;
inline int lowbit(int x){
return x&(-x);}
ll gcd(ll a,ll b){
return b?gcd(b,a%b):a;}
void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y){
if(!b){
d=a,x=1,y=0;}else{
ex_gcd(b,a%b,d,y,x);y-=x*(a/b);}}//x=(x%(b/d)+(b/d))%(b/d);
inline ll qpow(ll a,ll b,ll MOD=mod){
ll res=1;a%=MOD;while(b>0){
if(b&1)res=res*a%MOD;a=a*a%MOD;b>>=1;}return res;}
inline ll inv(ll x,ll p){
return qpow(x,p-2,p);}
inline ll Jos(ll n,ll k,ll s=1){
ll res=0;rep(i,1,n+1) res=(res+k)%i;return (res+s)%n;}
inline ll read(){
ll f = 1; ll x = 0;char ch = getchar();while(ch>'9'||ch<'0') {
if(ch=='-') f=-1; ch = getchar();}while(ch>='0'&&ch<='9') x = (x<<3) + (x<<1) + ch - '0', ch = getchar();return x*f; }
int dir[4][2] = {
{
1,0}, {
-1,0},{
0,1},{
0,-1} };
char s[20][20];
int grid[20][20];
int n,m;
vector<int> res;
int ans[200];
int mi = inf;
bool check()
{
rep(i,1,n) rep(j,1,m) if(grid[i][j]==0) return false;
return true;
}
void change(int order)
{
if(order>=1&&order<=n)
{
rep(j,1,m)
grid[order][j] = !grid[order][j];
}
else if(order>=n+1&&order<=n+m)
{
order -= n;
rep(i,1,n) grid[i][order] = !grid[i][order];
}
else
{
for(int i=n, j=1; i>=1&&j<=m; i--, j++)
grid[i][j] = !grid[i][j];
}
}
void dfs(int id)
{
if(check()) //看看有没有全变成1
{
if(res.size() < mi) //如果步数小于mi的话,更新
{
mi = res.size();
vector<int> tmp(res);
sort(tmp.begin(), tmp.end()); //按照字典序排序
for(int i=0; i<tmp.size(); i++) ans[i] = tmp[i];
}
else if(res.size()==mi) //如果等于,比较一下两者字典序
{
int flag = 0;
vector<int> tmp(res);
sort(tmp.begin(), tmp.end());
for(int i=0; i<tmp.size(); i++) if(tmp[i] < ans[i]) {
flag=1;break;} else break;
if(flag) for(int i=0; i<tmp.size(); i++) ans[i] = tmp[i];
}
return;
}
if(id>n+m+1) return;
//当前id指令选
change(id); //改变矩阵
res.pb(id); //记录一下
dfs(id+1); //然后遍历下一个指令
res.pop_back(); //回溯回来
change(id);
//当前id指令不选
dfs(id+1);
}
int main()
{
int kase;
cin>>kase;
while(kase--)
{
res.clear(); mi = inf;
scanf("%d%d",&n,&m);
rep(i,1,n) scanf("%s",(s[i]+1));
rep(i,1,n) rep(j,1,m) grid[i][j] = s[i][j] - '0';
dfs(1);
if(mi==inf)
{
cout<<"JustGoToPlayToTheMoon"<<'\n';
continue;
}
cout<<mi<<'\n';
for(int i=0; i<mi; i++) printf("%d%c",ans[i],i==mi-1?'\n':' ');
}
return 0;
}
思路:很中规中矩的模拟题。题目要我们做什么就做什么就好了。
1.我们用一个map记录m种原料各个所需要的个数。
2.用一个结构体记录k种饮料,每个饮料包含的信息(变量)有饮料名称,所需要的原料及个数(用一个map同上),以及是否为大杯(bool型)。
3.然后n个人遍历,他要什么饮料,我们就套个循环找到那个饮料,然后看看杯型是否对的上,对不上就调一下杯型同时原料乘2(若本身就大杯就只能大杯)。
大概就这样,注意一下细节应该就没啥大问题。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define FAST ios::sync_with_stdio(false)
#define abs(a) ((a)>=0?(a):-(a))
#define sz(x) ((int)(x).size())
#define all(x) (x).begin(),(x).end()
#define mem(a,b) memset(a,b,sizeof(a))
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define rep(i,a,n) for(int i=a;i<=n;++i)
#define per(i,n,a) for(int i=n;i>=a;--i)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<ll,ll> PII;
const int maxn = 1e5+200;
const int inf=0x3f3f3f3f;
const double eps = 1e-7;
const double pi=acos(-1.0);
const int mod = 1e9+7;
inline int lowbit(int x){
return x&(-x);}
ll gcd(ll a,ll b){
return b?gcd(b,a%b):a;}
void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y){
if(!b){
d=a,x=1,y=0;}else{
ex_gcd(b,a%b,d,y,x);y-=x*(a/b);}}//x=(x%(b/d)+(b/d))%(b/d);
inline ll qpow(ll a,ll b,ll MOD=mod){
ll res=1;a%=MOD;while(b>0){
if(b&1)res=res*a%MOD;a=a*a%MOD;b>>=1;}return res;}
inline ll inv(ll x,ll p){
return qpow(x,p-2,p);}
inline ll Jos(ll n,ll k,ll s=1){
ll res=0;rep(i,1,n+1) res=(res+k)%i;return (res+s)%n;}
inline int read(){
int f = 1; int x = 0;char ch = getchar();while(ch>'9'||ch<'0') {
if(ch=='-') f=-1; ch = getchar();}while(ch>='0'&&ch<='9') x = (x<<3) + (x<<1) + ch - '0', ch = getchar();return x*f; }
int dir[4][2] = {
{
1,0}, {
-1,0},{
0,1},{
0,-1} };
int n,m,k;
map<string,int> cnt; //cnt用来存储原料用了多少
typedef struct Drink //Drink结构体用来存k种饮料的名称、原料及个数、是否大杯
{
string name;
map<string,int> mat;
bool large;
}D;
D a[500];
int main()
{
int kase;
cin>>kase;
while(kase--)
{
cnt.clear();
scanf("%d%d%d",&n,&m,&k);
vector<string> item; //记录输入的m种原料
rep(i,1,m)
{
string s;
cin>>s;
item.pb(s);
}
rep(i,1,k) a[i].mat.clear(); //初始化
rep(i,1,k)
{
cin>>a[i].name; //读入饮料名
int x = read(); //原料个数
int sum = 0; //统计总原料瓶数
rep(j,1,x)
{
string s; cin>>s; //当前原料名
int num = read();
a[i].mat[s] += num; //计数
sum += num;
}
if(sum > 10) a[i].large = true; else a[i].large = false; //判断是否为大杯
}
rep(i,1,n)
{
string name;
cin>>name;
int flag = read();
rep(j,1,k) //在k种饮料中找到当前客人要的
{
if(a[j].name==name)
{
if(a[j].large||a[j].large==flag) //本身是大杯或者杯型和要求一致就不加倍
{
for(auto it = a[j].mat.begin(); it != a[j].mat.end(); it++)
cnt[it->fi] += it->se;
}
else //否则加倍
{
for(auto it = a[j].mat.begin(); it != a[j].mat.end(); it++)
cnt[it->fi] += 2*it->se;
}
}
}
}
for(int i=0; i<item.size();i++)
printf("%d%c",cnt[item[i]], i==item.size()-1?'\n':' ');
}
return 0;
}
思路:这个题似乎没什么技巧了。比命长的题,无限if-else。挑最大值的时候尽量选能进位的,最小值时则反过来。我写的代码太丑了这里贴上队友@LEO的代码。似乎这个题有更简便的方法,如果读者有更好的方法欢迎评论区讨论。
#include
#include
int main()
{
int T,g;
scanf("%d",&T);
getchar();
for(g=1;g<=T;g++)//案例
{
char fs[8];
int a[3],b[3],j=0,max1=0,min1=0,w,i,c[3],d[3];
gets(fs);
scanf("%d",&w);
getchar();
for(i=0;i<7;i++)//将分数分为两段
{
if(i<3)
{
a[j]=fs[i]-48;
c[j]=a[j];
j++;
if(i==2) j=0;
}
else if(i>3)
{
b[j]=fs[i]-48;
d[j]=b[j];
j++;
}
}
for(i=0;i<w;i++)
{
if(a[1]*10+a[2]+w-i>=100&&b[1]*10+b[2]+w-i>=100)//两方都能进百位
{
if(a[1]*10+a[2]>=b[1]*10+b[2])//进大的数
{
a[2]+=1;
if(a[2]==10)
{
a[2]=0;
a[1]+=1;
if(a[1]==10)
{
a[1]=0;
max1+=19;
}
else max1+=10;
}
else max1+=1;
}
else//进大的数
{
b[2]+=1;
if(b[2]==10)
{
b[2]=0;
b[1]+=1;
if(b[1]==10)
{
b[1]=0;
max1+=19;
}
else max1+=10;
}
else max1+=1;
}
}
else if(a[1]*10+a[2]+w-i>=100&&b[1]*10+b[2]+w-i<100)//一方能进百位
{
a[2]+=1;
if(a[2]==10)
{
a[2]=0;
a[1]+=1;
if(a[1]==10)
{
a[1]=0;
max1+=19;
}
else max1+=10;
}
else max1+=1;
}
else if(a[1]*10+a[2]+w-i<100&&b[1]*10+b[2]+w-i>=100)//一方能进百位
{
b[2]+=1;
if(b[2]==10)
{
b[2]=0;
b[1]+=1;
if(b[1]==10)
{
b[1]=0;
max1+=19;
}
else max1+=10;
}
else max1+=1;
}
else if(a[2]+w-i>=10&&b[2]+w-i>=10)//两个都能进十位
{
if(a[2]>=b[2])
{
a[2]+=1;
if(a[2]==10)
{
a[2]=0;
max1+=10;
}
else max1+=1;
}
else
{
b[2]+=1;
if(b[2]==10)
{
b[2]=0;
max1+=10;
}
else max1+=1;
}
}
else if(a[2]+w-i>=10&&b[2]+w-i<10)//一个能进十位
{
a[2]+=1;
if(a[2]==10)
{
a[2]=0;
max1+=10;
}
else max1+=1;
}
else if(a[2]+w-i<10&&b[2]+w-i>=10)//一个能进十位
{
b[2]+=1;
if(b[2]==10)
{
b[2]=0;
max1+=10;
}
else max1+=1;
}
else if(a[2]+w-i<10&&b[2]+w-i<10)//两个都不能进十位
{
max1+=1;
}
//最小值
if(c[2]<9)
{
c[2]+=1;
min1+=1;
}
else if(d[2]<9)
{
d[2]+=1;
min1+=1;
}
else if(c[2]==9&&d[2]==9)
{
if(c[1]>d[1])
{
d[2]=0;
d[1]+=1;
min1+=10;
}
else
{
c[2]=0;
c[1]+=1;
if(c[1]==10)
{
c[1]=0;
min1+=19;
}
else min1+=10;
}
}
}
printf("Case %d: %d %d\n",g,max1,min1);
}
return 0;
}