杭电第三场题解

1012 Cyber Language

​ 给定一串字符将首字母大写

签到题

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int INF=0x3f3f3f3f;
const int mod=1e3+7;
const int N=1e3+5,M=5e5+5;

int n,m;
string str;

int main(){
    int T;
    cin>>T;
    getchar();
    while(T--) {
        getline(cin,str);
        string ans="";
        for(int i=0;i<str.length();i++) {
            if(i==0) ans+=str[i]-32;
            else if(str[i]==' '&&i!=str.length()-1) ans+=str[i+1]-32;
        }
        cout<<ans<<endl;
    }
	return 0;
}

1009 Package Delivery

有n个包裹,每个包裹有对应的起止时间,在规定时间内可领取,一次最多能领k个包裹,问最少要取几次

考虑r最小的那个区间k,第一次取快递放在第rk天一定不会使结果变差。此时可能有很
多区间覆盖了rk,那么为了尽量延后下一次取快递的日期,此时的最优策略应该是选择覆盖rk且 r 值最小的 k 个区间,使用堆找到并去掉这些区间后,问题就递归了。重复上述过程直至处理完所有n个区间。
时间复杂度 O(n log n)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int INF=0x3f3f3f3f;
const int mod=1e3+7;
const int N=1e5+5,M=5e5+5;

int n,m,k;
struct node{
    int l,r,id;
    bool operator < (const node &b) const {
        if(r==b.r) return l>b.l;
		return r > b.r; //从大到小
	}
};

struct node p[N],q[N];
bool st[N];

bool cmp1(struct node a,struct node b) {
    if(a.r==b.r) return a.l<b.l;
    return a.r<b.r;
}

bool cmp2(struct node a,struct node b) {
    if(a.l==b.l) return a.r<b.r;
    return a.l<b.l;
}

int check() {
    int pos=1,pos2=1,t=0,r;
    priority_queue<node> heap;
    int cnt=0;
    while(pos<=n) {
        if(st[p[pos].id]) {
            pos++;
            continue;
        }
        st[p[pos].id]=1;
        r=p[pos].r;
        pos++; t++;
        while(pos2<=n) {
            if(st[q[pos2].id]) {
                pos2++;
                continue;
            }
            if(q[pos2].l>r) break;
            heap.push(q[pos2++]);
        }
        while(heap.size()&&t<k) {
            node tt=heap.top(); heap.pop();
            if(st[tt.id]||tt.r<r) continue;
            st[tt.id]=1;
            t++;
        }
        t=0;
        cnt++;
    }
    return cnt;
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    int T;
    scanf("%d",&T);
    while(T--) {
       memset(st,0,sizeof(st));
       scanf("%d%d",&n,&k);
       //printf("%d %d\n",n,k);
       int a,b;
       for(int i=1;i<=n;i++) {
            scanf("%d%d",&a,&b);
            p[i]={a,b,i};
            q[i]={a,b,i};
       }
       sort(p+1,p+n+1,cmp1);
       sort(q+1,q+n+1,cmp2);
       printf("%d\n",check());
    }
	return 0;
}

1012 Two Permutations

给定两个排列队列 P,Q ,求出队后形成序列 S 的方案数量。
 
首先特判序列 S 中每个数字出现次数不都为 2 的情况,此时答案为 0
动态规划,设 f i,j 表示 P 的前 i 项匹配上了 S ,且 P i 匹配 S 中数字 P i j 次出现的位
置时,有多少种合法的方案。由于 S 中每个数字出现次数都为 2 ,因此状态数为 O ( n ) 。转移时
枚举 P i +1 匹配哪个位置,那么 P i 匹配的位置与 P i +1 匹配的位置中间的那段连续子串需要完
全匹配 Q 中对应的子串,使用字符串 Hash 进行 O (1) 判断即可。
时间复杂度 O ( n )
#include<bits/stdc++.h>
using namespace std;
template <typename tn>void read(tn &n){
    tn f=1,t=0;char ch=getchar();
    while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
    while (isdigit(ch)) t=t*10+ch-'0',ch=getchar();
    n=f*t;
}
inline void out(int x){
	if(x>9)out(x/10);
	putchar(x%10+'0');
}
int p[301000],q[301000],s[601000],T,n,x[5],y[5];
long long dpp[5],dppp[5],mo=998244353998244353;
int main(){
	read(T);
	while(T--){
		read(n);
		for(register int i=1;i<=n;++i)read(p[i]);
		for(register int i=1;i<=n;++i)read(q[i]);
		for(register int i=1;i<=2*n;++i)read(s[i]);
		x[1]=1;
		if(s[1]==p[1])dpp[1]=1;
		x[2]=0;
		if(s[1]==q[1])dpp[2]=1;
		bool f=false;
		for(register int i=2;i<=2*n;++i){
			int point=1;
			for(register int j=0;j<=i;++j){
				if((j!=x[1])&&(j!=x[1]+1)&&(j!=x[2])&&(j!=x[2]+1))continue;
				int dp=0;
				if(s[i]==p[j]){
					if(j==x[1]+1)dp=dpp[1];
					if(j==x[2]+1)dp=dpp[2];
				}
				if(s[i]==q[i-j]){
					if(j==x[1])dp+=dpp[2];
					if(j==x[2])dp+=dpp[1];
				}
				if(dp>0){
					y[point]=j;
					dppp[point]=dp;
					if(dppp[point]>mo)dppp[point]%=mo;
					point++;
				}
			}
			for(int j=1;j<=2;++j)x[j]=y[j],dpp[j]=dppp[j];
			if(point==1){f=true;break;}
			if(point==2)x[2]=-2,dpp[2]=0;
		}
		if(f)cout<<"0"<<endl;
		else cout<<dpp[1]<<endl;
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值