链接:Circus
题意:
给a,b两个字符串,代表n名演员是否会小丑和杂技
1代表表演小丑, 0 代表表演杂技,1 代表两个都表演, 0 代表两个都不表演
0 , 1 ,1 , 0
要求选择n/2个演员在第一场演出,使得第一场的小丑和第二次的杂技数目相同
解析
可以直接暴力
遍历a和c的数目i,j
(i+j)是第一场上场的小丑,也是第二次上场的杂技的数目
b-((i+j)-(c-j)) 代表 在第一场上场的只会杂技的数目,(i+j)为第二场的杂技人员,((i+j)-(c-j))在第二场上场的只会杂技的人数
化简就是b+c-i-2*j
ac:
#include<bits/stdc++.h>
#define pb push_back
#define MAXN 5005
using namespace std;
char str[MAXN],ctr[MAXN];
int main()
{
ios::sync_with_stdio(false);
int n;
cin>>n;
cin>>str+1>>ctr+1;
vector<int> aa,bb,cc,dd;
for(int i=1;i<=n;i++)
{
if(str[i]=='1'&&ctr[i]=='0')
aa.pb(i);
else if(str[i]=='0'&&ctr[i]=='1')
bb.pb(i);
else if(str[i]=='1'&&ctr[i]=='1')
cc.pb(i);
else if(str[i]=='0'&&ctr[i]=='0')
dd.pb(i);
}
for(int i=0;i<=(int)aa.size();i++)//a的数目
{
for(int j=0;j<=(int)cc.size();j++)//c的数目
{
int k=(int)bb.size()+(int)cc.size()-i-2*j;//b的数目
if(k>=0&&k<=(int)bb.size())
{
int l=n/2-i-j-k;//d的数目
if(l>=0&&l<=(int)dd.size())
{
for(int a=0;a<i;a++)
cout<<aa[a]<<" ";
for(int b=0;b<j;b++)
cout<<cc[b]<<" ";
for(int c=0;c<k;c++)
cout<<bb[c]<<" ";
for(int d=0;d<l;d++)
cout<<dd[d]<<(d==l-1?"\n":" ");
return 0;
}
}
}
}
printf("-1\n");
return 0;
}
分宿舍:http://acm.hdu.edu.cn/showproblem.php?pid=6492
小伙们打算组团去参加。他们一共有 n+m+2k 个人,包括 n+k 个男生,m+k 个女生,其中 k 对男女生为异性情侣,现在他们要找房间住。房间有三种类型,双人间 a 元一间,三人间 b 元一间,这两种只能同性一起住。情侣间能住一对异性情侣,一间 c 元。除了情侣间以外,其他房间都可以不住满。
求最少花多少钱,能让小伙伴们都有地方住。
解析:
直接暴力遍历
先暴力k,然后暴力双人间,通过双人间可以直接算出三人间,注意精度
ac:
#include<bits/stdc++.h>
#define ll long long
#define MAXN 1005
using namespace std;
int main()
{
ll t,n,m,k,a,b,c,nn,mm,kk;
scanf("%d",&t);
while(t--)
{
scanf("%lld%lld%lld%lld%lld%lld",&nn,&mm,&kk,&a,&b,&c);
ll ans=1e15;
ll sum;
for(ll i=0;i<=kk;i++)
{
sum=0;
n=nn+kk-i;
m=mm+kk-i;
sum+=i*c;
ll aa=n/2+n%2;
ll dd=1e15;
if(aa)
{
for(ll j=0;j<=aa;j++)
{
ll cc=(n-2*j)%3;
if(cc<0)
cc=0;
dd=min(dd,j*a+b*((n-2*j)/3+(cc!=0)));
}
sum=sum+dd;
}
ll bb=m/2+m%2;
dd=1e15;
if(bb)
{
for(ll j=0;j<=bb;j++)
{
ll cc=(m-2*j)%3;
if(cc<0)
cc=0;
dd=min(dd,j*a+b*((m-2*j)/3+(cc!=0)));
}
sum+=dd;
}
ans=min(ans,sum);
}
printf("%lld\n",ans);
}
return 0;
}
题意:
给定1个数组,让你选若干个数,这些数的和为k
输出一个串长为该数组,该串1表示选择,0表示不选择
解析:
如果直接暴力枚举每种情况,呢么复杂度为2^36,显然不行
我们可以将串分为两部分,我们先求左边的,复杂度2^18
然后枚举右边的情况,2^18,如果s-右边的,在左边出现过,这样分配就可行
总的复杂度位2*2^18.
这样暴力就降低1维,这和枚举降维一个道理
<<和>>的优先级小于+,-,x,/
ac:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll a[38];
unordered_map<ll,int> hash1;
int main()
{
int n;
ll s;
scanf("%d%lld",&n,&s);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
int m=n/2;
for(int i=0;i<=(1<<m)-1;i++)
{
ll sum=0;
for(int k=0;k<=m-1;k++)
{
if((i>>k)&1==1)
sum+=a[k+1];
}
hash1[sum]=i;
}
int kk=n-m;
for(int i=0;i<=(1<<kk)-1;i++)
{
ll sum=0;
for(int k=0;k<=kk-1;k++)
{
if((i>>k)&1==1)
sum+=a[k+1+m];
}
if(sum==s||hash1[s-sum]!=0)
{
ll q=hash1[s-sum];
for(int j=0;j<=m-1;j++)
printf("%d",(q>>j)&1);
for(int j=0;j<=kk-1;j++)
printf("%d",(i>>j)&1);
printf("\n");
break;
}
}
return 0;
}
题意:
给定一个数组,你可以任选一个(l,r)中的数组元素删除,删除后剩下的数组元素都是唯一的(仅出现一次)
问你最小的(r-l+1)的大小
解析:
我用o(n)的方法被hack了,对于:6 3 1 4 3 2 4这组数据,解决不了
应当暴力处理这些区间
#include<bits/stdc++.h>
#define MAXN 2005
using namespace std;
int a[MAXN];
int b[MAXN];
int vis[MAXN];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),b[i]=a[i];
sort(b+1,b+n+1);
for(int i=1;i<=n;i++)
a[i]=lower_bound(b+1,b+n+1,a[i])-b;
//所以区间都要尝试一次,尝试能否在前面少取,而让后面可取更多
int ans=1e9;
for(int i=0;i<=n;i++)//i从0开始,尝试一次仅仅从后到前的遍历过程
{
memset(vis,0,sizeof(vis));
int ok=0;
for(int j=1;j<=i&&ok==0;j++)
{
if(vis[a[j]]==0)
vis[a[j]]=1;
else
ok=1;
}
if(ok)
break;
int p=i;
for(int j=n;j>i;j--)
{
if(vis[a[j]]){
p=j;
break;
}
else
vis[a[j]]=1;
}
ans=min(ans,p-i);
}
printf("%d\n",ans);
return 0;
}
http://acm.hdu.edu.cn/showproblem.php?pid=6739
Invoker
Time Limit: 15000/12000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Problem Description
在 dota2 中有一个叫做祈求者(Invoker)的英雄,在游戏中他有三个基础技能:冰(Quas),雷(Wex),火(Exort),每施展一个技能就可以获得相应属性的一个法球(element)。
但是祈求者同时最多只能有三个法球,即如果他在有三个法球的状态下又使用了某个法球技能,那么他会获得该法球,并失去之前三个法球中最先获得的一个。
不难得出,祈求者身上的三个法球的**无顺序**组合有 10 种,每一种都对应着一个组合技能:
1. 急速冷却(Cold Snap),无序组合 QQQ,用 Y 表示
2. 幽灵漫步(Ghost Walk),无序组合 QQW,用 V 表示
3. 寒冰之墙(Ice Wall),无序组合 QQE,用 G 表示
4. 电磁脉冲(EMP),无序组合 WWW,用 C 表示
5. 强袭飓风(Tornado),无序组合 QWW,用 X 表示
6. 灵动迅捷(Alacrity),无序组合 WWE,用 Z 表示
7. 阳炎冲击(Sun Strike),无序组合 EEE,用 T 表示
8. 熔炉精灵(Forge Spirit),无序组合 QEE,用 F 表示
9. 混沌陨石(Chaos Meteor),无序组合 WEE,用 D 表示
10. 超震声波(Deafening Blast),无序组合 QWE,用 B 表示
当祈求者拥有三个法球的时候,使用元素祈唤(Invoke)技能,用 R 表示,便可获得当前法球组合所对应的技能,同时原有的三个法球也不会消失,先后顺序的状态也不会改变。
现在给定一个技能序列,你想按照给定的顺序将他们一个一个地祈唤出来,同时你想用最少的按键来达到目标,所以你想知道对于给定的一个技能序列,最少按多少次键才能把他们都祈唤出来。
注意:游戏开始的时候,祈求者是没有任何法球的。
解析:
从前往后依次获得技能,要按顺序
我们暴力处理1->len的情况,最多计算6*6*100000次,我们预处理出每种字符串变化的最小步数,直接dp即可
ac:
#include<bits/stdc++.h>
#define ll long long
#define MAXN 1000005
using namespace std;
char s[MAXN];
int dp[MAXN][7];
int vv[11][7][11][7]={0};
string g[11][7];
int vg[30];
int gt(char x)//字母转数字
{
return vg[x-'A'];
}
void init()//预处理
{
vg['Y'-'A']=1;vg['V'-'A']=2;vg['G'-'A']=3;vg['C'-'A']=4;vg['X'-'A']=5;
vg['Z'-'A']=6;vg['T'-'A']=7;vg['F'-'A']=8;vg['D'-'A']=9;vg['B'-'A']=10;//将字符串转化为字母
g[1][1]="QQQ";g[1][2]="QQQ";g[1][3]="QQQ";g[1][4]="QQQ";g[1][5]="QQQ";g[1][6]="QQQ";
g[2][1]="QQW";g[2][2]="QWQ";g[2][3]="WQQ";g[2][4]="QQW";g[2][5]="QWQ";g[2][6]="WQQ";
g[3][1]="QQE";g[3][2]="QEQ";g[3][3]="EQQ";g[3][4]="QQE";g[3][5]="QEQ";g[3][6]="EQQ";
g[4][1]="WWW";g[4][2]="WWW";g[4][3]="WWW";g[4][4]="WWW";g[4][5]="WWW";g[4][6]="WWW";
g[5][1]="QWW";g[5][2]="WQW";g[5][3]="WWQ";g[5][4]="QWW";g[5][5]="WQW";g[5][6]="WWQ";
g[6][1]="WWE";g[6][2]="WEW";g[6][3]="EWW";g[6][4]="WWE";g[6][5]="WEW";g[6][6]="EWW";
g[7][1]="EEE";g[7][2]="EEE";g[7][3]="EEE";g[7][4]="EEE";g[7][5]="EEE";g[7][6]="EEE";
g[8][1]="QEE";g[8][2]="EQE";g[8][3]="EEQ";g[8][4]="QEE";g[8][5]="EQE";g[8][6]="EEQ";
g[9][1]="WEE";g[9][2]="EWE";g[9][3]="EEW";g[9][4]="WEE";g[9][5]="EWE";g[9][6]="EEW";
g[10][1]="QWE";g[10][2]="QEW";g[10][3]="WEQ";g[10][4]="EWQ";g[10][5]="WQE";g[10][6]="EQW";
for(int i=1;i<=10;i++)
{
for(int a=1;a<=6;a++)
{
for(int j=1;j<=10;j++)
{
for(int b=1;b<=6;b++)
{
if(g[i][a]==g[j][b])//全等
vv[i][a][j][b]=0;
else if(g[i][a][1]==g[j][b][0]&&g[i][a][2]==g[j][b][1])//消1个
vv[i][a][j][b]=1;
else if(g[i][a][2]==g[j][b][0])//消2个
vv[i][a][j][b]=2;
else //全消
vv[i][a][j][b]=3;
}
}
}
}
}
int main()
{
init();
while(scanf("%s",s+1)!=EOF)
{
int len=strlen(s+1);
for(int i=1;i<=6;i++)
dp[1][i]=4;//开始3个+1个R
for(int i=2;i<=len;i++)
for(int j=1;j<=6;j++)
dp[i][j]=1e9;
for(int i=2;i<=len;i++)//暴力遍历从1~len的所以变化情况
{
for(int j=1;j<=6;j++)
{
for(int k=1;k<=6;k++)
dp[i][j]=min(dp[i][j],dp[i-1][k]+vv[gt(s[i-1])][k][gt(s[i])][j]+1);//每次至少一个R
}
}
int ans=1e9;
for(int i=1;i<=6;i++)//取最小值
ans=min(dp[len][i],ans);
printf("%d\n",ans);
}
return 0;
}
https://blog.csdn.net/weixin_41183791/article/details/86622672#commentBox
https://codeforces.com/contest/1029/problem/C
题意:
有n条线段,让你删除一条,使得剩下的线段的公共长度最大,问最大值
解析:
枚举删除每条线段,判断最长公共长度
法1:
L保存左端,R保存右端
#include<bits/stdc++.h>
#define MAXN 300005
using namespace std;
struct node
{
int l,r;
}ee[MAXN];
unordered_map<int,int> visL,visR;
set<int> L,R;
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&ee[i].l,&ee[i].r);
L.insert(ee[i].l);
R.insert(ee[i].r);
if(visL[ee[i].l]==0)
visL[ee[i].l]=1;
else
visL[ee[i].l]++;
if(visR[ee[i].r]==0)
visR[ee[i].r]=1;
else
visR[ee[i].r]++;
}
if(n==1){
printf("%d\n",ee[1].r-ee[1].l+1);
return 0;
}
int maxs=0;
for(int i=1;i<=n;i++)
{
visL[ee[i].l]--;
visR[ee[i].r]--;
if(visL[ee[i].l]==0){
L.erase(ee[i].l);
}
if(visR[ee[i].r]==0){
R.erase(ee[i].r);
}
auto it=L.end();
it--;
int aa=*it;
int bb=*R.begin();
maxs=max(maxs,max(0,bb-aa+1));
visL[ee[i].l]++;
visR[ee[i].r]++;
if(visL[ee[i].l]==1){
L.insert(ee[i].l);
}
if(visR[ee[i].r]==1){
R.insert(ee[i].r);
}
}
if(maxs>0){
maxs--;
}
printf("%d\n",maxs);
return 0;
}
法2:
set二维操作,容易又简便很多
#include<bits/stdc++.h>
#define MAXN 300005
using namespace std;
struct node
{
int v,id;
friend bool operator<(node a,node b)
{
if(a.v==b.v)
return a.id<b.id;
return a.v<b.v;
}
};
struct vv
{
int l,r;
}ee[MAXN];
set<node> L,R;
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&ee[i].l,&ee[i].r);
L.insert(node{ee[i].l,i});
R.insert(node{ee[i].r,i});
}
if(n==1){
printf("%d\n",ee[1].r-ee[1].l+1);
return 0;
}
int maxs=0;
for(int i=1;i<=n;i++)
{
L.erase(node{ee[i].l,i});
R.erase(node{ee[i].r,i});
auto it=L.end();
it--;
int aa=it->v;
int bb=R.begin()->v;
maxs=max(maxs,max(0,bb-aa+1));
L.insert(node{ee[i].l,i});
R.insert(node{ee[i].r,i});
}
if(maxs>0)
maxs--;
printf("%d\n",maxs);
return 0;
}