0 压缩后缀数组
据传是水题
当f[i]=i时,原数组s的i位置一定是偶数,那么s[i]=a[对应的位置]*2
否则s[i]=s[f[i]]-1
#include <cstdio>
using namespace std;
int n;
int c[20004],a[20004],tot;
int s[20004];
int main(){
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d",&c[i]);
for (int i=1;i<=n/2;i++)
scanf("%d",&a[i]);
for (int i=1;i<=n;i++)
if (c[i]==i) s[i]=a[++tot]*2;
for (int i=1;i<=n;i++)
if (c[i]!=i)s[i]=s[c[i]]-1;
for (int i=1;i<=n;i++)
printf("%d ",s[i]);
}
1 新年礼物
Windbreaker计划送一些项链给他的朋友们作为新年礼物。为了表示诚意,他决定自己制作全部的项链。他购买了若干种珍珠,每种珍珠都有特定的颜色。他要制作的项链都是M-完美的,也就是每条项链都是恰好由M种珍珠组成的。Windbreaker想知道他最多能送出多少条项链。给定每种珍珠的数目,你要回答的是Windbreaker最多可以制作多少条M-完美项链。
我,应该是水过去的
就每次找出最大的m个数,都减去5(太小超时,太大错,所以说是水过去的啦),放进堆里;重复以上步骤知道堆内大于0的不足m个
#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
priority_queue<int> q;
int n,m,ans,d;
priority_queue<int> a;
int main(){
scanf("%d",&n);
while (n!=0){
while (!q.empty()) q.pop();
for (int i=1;i<=n;i++){
int x;
scanf("%d",&x);
q.push(x);
}
scanf("%d",&m);
ans=0;
while (!a.empty()) a.pop();
while (q.size()>=m){
for (int i=1;i<=m;i++){
a.push(-q.top());
q.pop();
}
if (!q.empty()) d=(-a.top()-q.top()+5); else d=-a.top();
if (d<0-a.top()) ans+=d; else d=-a.top(),ans+=d;
for (int i=1;i<=m;i++){
if (-a.top()-d>0) q.push(-a.top()-d);
a.pop();
}
}
printf("%d\n",ans);
scanf("%d",&n);
}
}
2 聚会
Tzdin想组织一个圣诞晚会。N位女士和M位男士(M>=N)会被邀请参加这个聚会。在聚会的开始,Tzdin会派发一些写着某位男士信息的卡片给每位女士;每位女士都会收到若干张这种卡片。然后每位女士可以从她收到的卡片里挑选一位男士作为她的伴侣。我们可以认为经过Tzdin的引导,每位女士都一定可以挑选到一位男士作为他的伴侣,而每位男士最多成为1位女士的伴侣。Tzdin想知道的是,有哪些男士,无论女士们怎么选择,最终都一定会拥有伴侣。
想到是匈牙利算法了呀,方法错了呗:P
应该先找出最大匹配,然后对于每个女士,让她不和在最大匹配中的那位男士匹配,如果此时她无法匹配,那么这个男士满足一定会有伴侣
毕竟最大匹配是
O
(
n
3
)
O(n^3)
O(n3)呀
#include <cstdio>
#include <cstring>
using namespace std;
const int N=1001;
int n,m;
int a[1003][1003];
bool b[1003],f[1003];
int s[1003],cover[1003];
int s2[1003];
bool dfs(int w){
for (int i=1;i<=a[w][0];i++)
if ((b[a[w][i]])&&(!cover[a[w][i]])){
int l=s[a[w][i]];
s[a[w][i]]=w;
cover[a[w][i]]=1;
if ((l==0)||(dfs(l))) return 1;
s[a[w][i]]=l;
}
return 0;
}
bool find(){
for (int i=1;i<=n;i++){
memset(cover,0,sizeof cover);
if (!dfs(i)) return 0;
}
return 1;
}
int main(){
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++){
scanf("%d",&a[i][0]);
for (int j=1;j<=a[i][0];j++)
scanf("%d",&a[i][j]);
}
memset(b,1,sizeof b);
memset(f,0,sizeof f);
find();
for (int i=1;i<=m;i++){
b[i]=0;
memset(cover,0,sizeof cover);
memcpy(s2,s,sizeof s2);
if ((s[i]!=0)&&(!dfs(s[i]))) f[i]=1;
b[i]=1;
memcpy(s,s2,sizeof s);
}
for (int i=1;i<=m;i++)
if (f[i])
printf("%d\n",i);
}
3 辽哥游戏
张辽是一个长发飘飘的非常聪明的男孩,人人都称他为“辽哥”。辽哥喜欢玩一个有趣的电脑游戏。这个游戏开始的时候有n个碉堡,每个碉堡拥有一个防御值和一个附加值。玩家拥有一个初始的攻击力。如果玩家破坏了一个碉堡,则他能得到1分。每一次,辽哥会选择一个碉堡进行攻击。所有未被破坏的碉堡会联合起来防御,因此为了破坏那个碉堡,辽哥的攻击力必须大于或者等于所有未被破坏的碉堡的防御值之和,否则辽哥就会输掉游戏。如果辽哥成功破坏了那个碉堡,那么他的攻击力会变成那个碉堡的附加值,然后他可以选择下一个攻击的目标。
由于辽哥拥有强大的编程能力,他不费吹灰之力就改写了那个游戏。在游戏开始前,他可以用炸弹消灭任意的碉堡,但是他不能通过这种方式来获得分数。问题来了,在游戏开始后,辽哥可以得到的最大分数是多少?
据闻是贪心加DP
炸掉碉堡就是不选择这些碉堡
设f[i]是剩下i个碉堡时所有碉堡最小的防御值
如果从前往后进行游戏很麻烦,所以
f[i]=min(f[i],f[i-1]+a[j]) {b[j]>=f[i-1]}
即这时还有i-1个碉堡,要选择上一个被炸的碉堡;这个被炸的碉堡,需要
防御值在可选的碉堡中最小
附加值大于已选的所有碉堡
排序就是按照a[i]+b[i]排序
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int n,l,r,ans,s;
struct node{
int f,g;
}a[1003];
int f[1003];
bool comp(node a,node b){
return a.f+a.g>b.f+b.g;
}
int main(){
while (~scanf("%d",&n)){
memset(a,0,sizeof a);
for (int i=1;i<=n;i++)
scanf("%d%d",&a[i].f,&a[i].g);
scanf("%d",&s);
sort(a+1,a+1+n,comp);
memset(f,0x3f,sizeof f);
f[0]=0;
for (int i=n;i;i--){
for (int j=n;j;j--)
if (a[i].g>f[j-1])
f[j]=min(f[j],f[j-1]+a[i].f);
}
l=0,r=n;
while (l<=r){
int mid=(l+r)/2;
if (f[mid]<=s) ans=mid,l=mid+1;
else r=mid-1;
}
printf("%d\n",ans);
}
}
立阳二中、清华医学系谢俞
“我是谢俞。还有,我不涂黑指甲油”