P1098 [NOIP2007 提高组] 字符串的展开
(1) 遇到下面的情况需要做字符串的展开:在输入的字符串中,出现了减号 -
,减号两侧同为小写字母或同为数字,且按照 ASCII
码的顺序,减号右边的字符严格大于左边的字符。
(2) 参数 p1:展开方式。p1=1 时,对于字母子串,填充小写字母;p1=2 时,对于字母子串,填充大写字母。这两种情况下数字子串的填充方式相同。p1=3 时,不论是字母子串还是数字字串,都用与要填充的字母个数相同的星号 *
来填充。
(3) 参数 p2:填充字符的重复个数。p2=k 表示同一个字符要连续填充 k 个。例如,当p2=3 时,子串d-h
应扩展为 deeefffgggh
。减号两边的字符不变。
(4) 参数 p3:是否改为逆序:p3=1 表示维持原来顺序,p3=2 表示采用逆序输出,注意这时候仍然不包括减号两端的字符。例如当 p1=1、p2=2、p3=2 时,子串 d-h
应扩展为 dggffeeh
。
(5) 如果减号右边的字符恰好是左边字符的后继,只删除中间的减号,例如:d-e
应输出为 de
,3-4
应输出为 34
。如果减号右边的字符按照 ASCII
码的顺序小于或等于左边字符,输出时,要保留中间的减号,例如:d-d
应输出为 d-d
,3-1
应输出为 3-1
。
第 1 行为用空格隔开的 3 个正整数,依次表示参数 p1,p2,p3。
第 2 行为一行字符串,仅由数字、小写字母和减号 -
组成。行首和行末均无空格。
#include<bits/stdc++.h>
using namespace std;
int p1, p2, p3;
string s;
int main()
{
cin >> p1 >> p2 >> p3;
cin >> s;
int len = s.length();
for(int i=0; i<len; i++){
if(s[i]!='-'){cout << s[i]; continue;}//不是 '-' 输出
if((s[i-1]>='0'&&s[i-1]<='9')&&(s[i+1]<'0'||s[i+1]>'9')){cout << "-";continue;}//是 '-'不同类型,输出
if((s[i+1]>='0'&&s[i+1]<='9')&&(s[i-1]<'0'||s[i-1]>'9')){cout << "-";continue;}//是 '-'不同类型,输出
if(s[i-1] >= s[i+1]){cout << "-";continue;}//左大于右 输出
if(s[i-1]=='-' || s[i+1]=='-'){cout << "-";continue;}//两个连续 '-' 输出
if(s[i]=='-' && i==0){cout << "-";continue;}//第一个为 '-' 输出
if(p1==3 && i!=0){
for(char j=s[i-1]+1; j<s[i+1]; j++)
for(int k=1; k<=p2; k++)
cout << "*";
continue;
}
if(p3 == 1){ //顺时针
if(p1 == 1){ //小写
for(char j=s[i-1]+1; j<s[i+1]; j++)
for(int k=1; k<=p2; k++)
cout << char(j);
}if(p1 == 2){
for(char j=s[i-1]+1; j<s[i+1]; j++)
for(int k=1; k<=p2; k++){
if((s[i-1]>='0'&&s[i-1]<='9') || s[i+1]>='0'&&s[i+1]<='9')
cout << char(j);
else cout << char(j-32);
}
}
}
if(p3 == 2){ //逆时针
if(p1 == 1){ //小写
for(char j=s[i+1]-1; j>s[i-1]; j--)
for(int k=1; k<=p2; k++)
cout << char(j);
}if(p1 == 2){
for(char j=s[i+1]-1; j>s[i-1]; j--)
for(int k=1; k<=p2; k++){
if((s[i-1]>='0'&&s[i-1]<='9') || s[i+1]>='0'&&s[i+1]<='9')
cout << char(j);
else cout << char(j-32);
}
}
}
}
return 0;
}
P1065 [NOIP2006 提高组] 作业调度方案
一方面,每个操作的安排都要满足以下的两个约束条件。
-
对同一个工件,每道工序必须在它前面的工序完成后才能开始;
-
同一时刻每一台机器至多只能加工一个工件。
另一方面,在安排后面的操作时,不能改动前面已安排的操作的工作状态。
我们约定:在保证约束条件(1)(2)的条件下,尽量靠前插入
#include<bits/stdc++.h>
using namespace std;
int m, n, a[405], w[25][25], t[25][25];
// a:顺序,w[i][j]:i工件j工序需机器号,t[i][j]:i工件需j时间
int st[25][25], done[25], l[25][25], r[25][25], tot[25];
// st:每个工件每个工序最早开始时间,done:每个工件完成的工序数
// l:左端点,r右端点,tot:空隙时间
int main()
{
cin >> m >> n;
for(int i=1; i<=m*n; i++) cin >> a[i];
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
cin >> w[i][j];
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
cin >> t[i][j];
//初始化空隙,每个机器有一个0到正无穷的空隙
for (int i=1; i<=m; i++) tot[i]=1, l[i][1]=0, r[i][1]=0x3f3f3f3f;
for(int k=1; k<=n*m; k++) {
int job = a[k]; //当前的工作
int process = done[job] + 1; //通过已完成的工序数能得到当前是第几个工序
int number = w[job][process]; //该工序的机器编号
for(int i=1; i<=tot[number]; i++) { //枚举空隙
if(l[number][i] < st[job][process] && st[job][process] + t[job][process] <= r[number][i]){
//当前工序能从最早开工时间开始
//空隙需要包含整个工作时间
//如果符合条件,当前空隙会被工作过程再分成两个小空隙,以下即处理
tot[number]++; //空隙数+1
for(int j=tot[number]; j>i+1; j--)
l[number][j] = l[number][j-1], r[number][j] = r[number][j-1];
//把后面的空隙往后挪一位
st[job][process+1] = st[job][process] + t[job][process];
//当前工作的下一个工序的最早开工时间也能得出了
l[number][i+1] = st[job][process+1];
//多的一个空隙的左端点即当前工序的结束时间即下一个工序的最早开工时间
r[number][i+1] = r[number][i];
//多的一个空隙的右端点即原空隙的右端点
r[number][i] = st[job][process];
//原空隙的右端点即当前工序的开工时间
break;
}
else if(l[number][i] >= st[job][process] && l[number][i]+t[job][process] <= r[number][i]) {
//当前工序不能从最早开工时间开始
//则空隙的大小得大于等于工作的时间
st[job][process+1] = l[number][i] + t[job][process];
//当前工作的下一个工序的时间同样也可以得出了
l[number][i] += t[job][process];
//左端点往后挪
break;
}
}
done[job]++; //当前工作完成了一个工序
}
int ans=0;
for (int i=1; i<=m; i++) ans=max(ans, l[i][tot[i]]);
//每台机器的最后一个空隙是 这台机器上最后一个加工的工序的结束时间到正无穷
//所以答案即所有机器的最后一个空隙的左端点的最大值
cout << ans << endl;
return 0;
}