题面
T1:
T2:
T3:
T4:
题解
T1:
难度不高,但要仔细想想。
思路:
先按截稿时间由小到大排序,这样能使截稿晚的能余出时间照顾截稿早的。
①:从第一个开始,若(当前任务需要的时间+之前的总时间)<=当前任务的截稿时间,则扔进堆里,ans++。
②:若(当前任务需要的时间+之前的总时间)>当前任务的截稿时间,这时要从它前面所有任务中选一个所需时间最长的(记为y)和它比较,
若当前任务所需时间 > y,则不扔进堆中。
若当前任务所需时间 < y,则把y替换成当前任务。
这样能保证时间利用率最高,完成更多的任务。
代码
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int size=200010;
struct edge{
int a,b;
}l[size];
bool cmp(edge a,edge b)
{
return a.b==b.b? a.a<b.a :a.b<b.b;//设置排序主要、次要关键字。
}
priority_queue<edge> q;
bool operator <(edge a,edge b)
{
return a.a<b.a;
}
int main()
{
freopen("alma.in","r",stdin);
freopen("alma.out","w",stdout);
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&l[i].a,&l[i].b);//输入数据。
}
sort(l+1,l+1+n,cmp);//排序。
int ans=0,tot=0;//tot记录当前总时间
for(int i=1;i<=n;i++)
{
if(l[i].a+tot<=l[i].b) //当前时间加上总时间小于截稿时间。
{
ans++;q.push(l[i]);tot+=l[i].a;
}
else//②,这种情况下ans不变。
{
edge x=q.top(); q.pop();//取出堆里所需时间最长的。
tot-=x.a;
if(l[i].a<x.a) {q.push(l[i]);tot+=l[i].a;}
else {q.push(x); tot+=x.a;}
}
}
printf("%d",ans);
fclose(stdin);
fclose(stdout);
return 0;
}
T2:
T3:
大家可能没有看懂题面,但看到样例一定就知道这题是什么意思了←_←。
一道字符串DP,在DP中难度不是很大,下面简单介绍一下思路。
思路一:
离线处理,先把给出的文章记录下来,然后想怎样设计状态。
读入用string吧,方便。
可是string的下标是从0开始的怎么办?
string s="*",t;
while(cin>>t)//读入
s+=t;//把多段字符串拼成一个。
t="*HELLOWORLD";
这样s就是我们的文章了。
大小写怎么办?
既然上面的HELLOWORLD用了大写,那么我们也全转大写好了。
for(int i=1;i<=l;i++)//转换为大写
if(s[i]>='a')
s[i]-=32;
大小写搞完了。
怎么设计状态呢?
想啊想~~~
好难啊QAQ
我们可以挨个匹配“helloworld”啊。(重点来了,记笔记记笔记)
于是设计状态f[i][j]表示,原字符串匹配到第 i 个字符,helloworld匹配到第 j 个字符时的方案数 。
先转移f[i][j]=f[i-1][j];
如果当前字符匹配到了helloworld里的某个字符(即s[i]==t[j]),那么就转移f[i][j]+=f[i-1][j-1];
然后把f[i][j]%=MOD;
这样转移部分就写完了。
然后——
i 和 j 的for循环,哪个套在外面呢?想一想。
答案是——
都一样。
“拿s与t匹配”和“拿t与s匹配”得到的结果不是一样么
代码
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
using namespace std;
const int N=500005;
const int mod=1000000007;
int l,f[N][15];//设f[i][j]表示,原字符串匹配到i,helloworld匹配到j的方案数 。
string s,t;//读入用string类型会十分方便。
int main()
{
s="*";
while(cin>>t)//读入
s+=t;
t="*HELLOWORLD";
l=s.length()-1;
for(int i=1;i<=l;i++)//转换为大写
if(s[i]>='a')
s[i]-=32;
for(int i=0;i<=l;i++)
f[i][0]=1;//初始化f[i][0]=1(0<=i<=l)
for(int i=1;i<=l;i++)
for(int j=1;j<=10;j++)
{
f[i][j]=f[i-1][j];//首先,f[i][j]=f[i-1][j];
if(s[i]==t[j])//其次,如果s[i]==t[j],就可以转移,f[i][j]+=f[i-1][j-1];
f[i][j]+=f[i-1][j-1],f[i][j]%=mod;
}
printf("%d\n",f[l][10]);
return 0;
}
运行结果
思路二:
在线处理,既然我们上面说了“拿s与t匹配”和“拿t与s匹配”得到的结果是一样的,那么我们一个一个的读字符,拿它与“helloworld”比较。
这样的话第二维我们就不需要了=v= 去掉去掉
于是原f[i][j]变成了dp[i]。
然后大小写我们这样:
if(c==t[i]||c+32==t[i])//t里面是"helloworld"
最后,我们把原先正的搜索顺序改为倒序(原因参考DQS学长的背包问题课件)。
这样我们只需要满足条件时转移dp[i]=dp(dp[i-1]+dp[i])%MOD就可以了。
代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
const int mod=1000000007;
int main()
{
freopen("helloworld.in","r",stdin);
freopen("helloworld.out","w",stdout);
long long dp[11]={1};
char c,hello[20]="?helloworld";
while((c=getchar())!=EOF)
{
for(int i=10;i>=1;i--)
if(c==hello[i]||c+32==hello[i])
dp[i]=(dp[i-1]+dp[i])%mod;
}
cout<<dp[10];
fclose(stdin);
fclose(stdout);
return 0;
}
运行结果
这里可以很明显的看出第二种方法(共0.19s)在处理大数据时的时间效率要远高于第一种方法(共1.73s)。