Codeforces Good Bye 2015 ABCDE

果然到了年末,智商余额不足,无限崩盘。

A New Year and Days

对着新年日历看一下,分类输出各种情况即可。

#include <bits/stdc++.h>

using namespace std;

#define ll long long

int main(){
    int n;
    cin>>n;
    string q;
    string str;
    cin>>q;
    cin>>str;

    if(str=="week"){
        if(n<=4||n==7){
            cout<<52<<endl;
        }else{
            cout<<53<<endl;
        }
    }else{
        if(n<=29){
            cout<<12<<endl;
        }else if(n<=30){
            cout<<11<<endl;
        }else{
            cout<<7<<endl;
        }
    }
    return 0;
}

B New Year and Old Property

把符合条件的数,用位运算预处理出来,然后计数。

#include <bits/stdc++.h>

using namespace std;

#define ll long long

ll tab[5555];

int main(){
    ll a,b;
    cin>>a>>b;
    int k=0;
    for(ll i=2;i<61;i++){
        ll tmp = (1LL<<i) - 1;
        for(int j=0;j<i-1;j++){
            ll m = 1LL<<j;
            ll cur = tmp^m;
            tab[k++]=cur;
        }
    }
    ll ans = 0;
    for(int i=0;i<k;i++){
        if(tab[i]>= a && tab[i]<=b){
            ans++;
        }
    }
    cout<<ans<<endl;
    return 0;
}

C New Year and Domino

利用前缀和,计算从左上角到每个格子有多少种放法。然后利用容斥原理拿4个矩形算一下,注意处理边界。

#include <bits/stdc++.h>

using namespace std;

#define ll long long

char mp[555][555];
int cnt1[555][555];
int cnt2[555][555];
int ans[555][555];

int main(){
    int h,w;
    cin>>h>>w;

    for(int i=1;i<=h;i++){
        scanf("%s",mp[i]+1);
    }

    for(int i=2;i<=h;i++){
        for(int j=1;j<=w;j++){
            if(mp[i][j]=='.' && mp[i-1][j]=='.'){
                cnt1[i][j]=cnt1[i-1][j]+1;
            }else{
                cnt1[i][j]=cnt1[i-1][j];
            }
        }
    }

    for(int i=2;i<=w;i++){
        for(int j=1;j<=h;j++){
            if(mp[j][i]=='.' && mp[j][i-1]=='.'){
                cnt2[j][i]=cnt2[j][i-1]+1;
            }else{
                cnt2[j][i]=cnt2[j][i-1];
            }
        }
    }
    
    for(int i=1;i<=h;i++){
        for(int j=2;j<=w;j++){
            cnt1[i][j]+=cnt1[i][j-1];
        }
    }

    for(int i=1;i<=w;i++){
        for(int j=2;j<=h;j++){
            cnt2[j][i]+=cnt2[j-1][i];
        }
    }

    for(int i=1;i<=h;i++){
        for(int j=1;j<=w;j++){
            ans[i][j] = cnt1[i][j] + cnt2[i][j];
        }
    }

    int q;
    cin>>q;
    while(q--){
        int x1,y1,x2,y2;
        scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
        int res = ans[x2][y2]-ans[x1-1][y2]-ans[x2][y1-1]+ans[x1-1][y1-1];
        for(int i=x1;i<=x2;i++){
            if(mp[i][y1]=='.'&&mp[i][y1-1]=='.')res--;
        }
        for(int i=y1;i<=y2;i++){
            if(mp[x1][i]=='.'&&mp[x1-1][i]=='.')res--;
        }
        printf("%d\n",res);
    }

    return 0;
}

D New Year and Ancient Prophecy

dp。dp(i,j)表示考察到第i个字符,最后一段长度为j的方案数。dp(i,j)显然由dp(i-j,k)转移而来,k可以取若干个值,需要优化避免重复计算。另外由于后一个数需要严格大于前一个数,也就是涉及到最后两个数的大小比较,同样需要优化,原理类似。详见代码。

#include <bits/stdc++.h>

using namespace std;

#define ll long long

const int mod = 1e9+7;

char num[5010];

int dp[5010][5010]; 
int sum[5010][5010];
pair<int,int> cmp[5010][5010];

int isLE(int a,int b,int c,int d){
    int len = b-a+1;

    int i=0;
    if(a>0){
        pair<int,int> pre = cmp[a-1][len];
        if(pre.second){ 
            if(pre.first){  
                cmp[a][len].first = pre.first;
                cmp[a][len].second = pre.second - 1;
                return pre.first;
            }else{          
                i= len-1 ;
            }
        }else{
            i=0;
        }
    }

    for(;i<len;i++){
        if(num[a+i]>num[c+i]){
            cmp[a][len].first = 1;
            cmp[a][len].second = i;
            return 1;
        }else if(num[a+i]<num[c+i]){
            cmp[a][len].first = -1;
            cmp[a][len].second = i;
            return -1;
        }
    }
    cmp[a][len].first = 0;
    cmp[a][len].second = len-1;
    return 0;
}

int main(){
    int n;
    cin>>n;
    scanf("%s",num);
    for(int i=0;i<n;i++){
        for(int j=i;j>=1;j--){  
            if(num[j]=='0'){
                dp[i][i-j+1]=0;
            }else{
                int start = j-1 - (i-j);
                if(start<0)start=0;
                if(j-1 - start == i-j){
                    if(isLE(start,j-1,j,i) >=0){
                        start++;
                    }
                }
                int tmp = sum[j-1][j-start];
                dp[i][i-j+1]+=tmp;
                dp[i][i-j+1]%=mod;
            }
            sum[i][i-j+1]=sum[i][i-j]+dp[i][i-j+1];
            sum[i][i-j+1]%=mod;
        }
        dp[i][i+1]=1;
        sum[i][i+1]=sum[i][i]+dp[i][i+1];
        sum[i][i+1]%=mod;
    }
    int ans = 0;
    for(int i=0;i<=n;i++){
        ans+=dp[n-1][i];
        ans%=mod;
    }
    cout<<ans<<endl;
    return 0;
}

E New Year and Three Musketeers

二分答案+贪心判断答案是否可行。二分部分不用说,解肯定在[n/3,n]这个区间。难点在于贪心,需要给火枪手和敌人排序,按从大到小的顺序处理敌人。敌人分配原则是,优先分配给弱的火枪手打,优先分配给更少的火枪手打。还要注意一个坑,答案不是三个火枪手的最长工作时间,因为可能会有人被迫等待,所以还要考虑协同作战的时间是否超出。

#include <bits/stdc++.h>

using namespace std;

#define ll long long

int m[10];
int t[200010];
int n;

bool judge(int x){
    int cnt[3]={0,0,0};
    int share = 0;
    for(int i=n-1;i>=0;i--){
        if(t[i]<=m[0]){
            if(cnt[0]<x){
                cnt[0]++;
            }else if(cnt[1]<x){
                cnt[1]++;
            }else if(cnt[2]<x){
                cnt[2]++;
            }else{
                return 0;
            }
        }else if(t[i]<=m[1]){
            if(cnt[1]<x){
                cnt[1]++;
            }else if(cnt[2]<x){
                cnt[2]++;
            }else{
                return 0;
            }
        }else if(t[i]<=m[2]){
            if(cnt[2]<x){
                cnt[2]++;
            }else if(t[i]<=m[0]+m[1] && cnt[0]<x && cnt[1]<x){
                cnt[0]++;
                cnt[1]++;
                share++;
            }else{
                return 0;
            }
        }else if(t[i]<=m[0]+m[1]){
            if(cnt[0]<x && cnt[1]<x){
                cnt[0]++;
                cnt[1]++;
                share++;
            }else if(cnt[0]<x && cnt[2]<x){
                cnt[0]++;
                cnt[2]++;
                share++;
            }else if(cnt[1]<x && cnt[2]<x){
                cnt[1]++;
                cnt[2]++;
                share++;
            }else{
                return 0;
            }
        }else if(t[i]<=m[0]+m[2]){
            if(cnt[0]<x && cnt[2]<x){
                cnt[0]++;
                cnt[2]++;
                share++;
            }else if(cnt[1]<x && cnt[2]<x){
                cnt[1]++;
                cnt[2]++;
                share++;
            }else{
                return 0;
            }
        }else if(t[i]<=m[1]+m[2]){
            if(cnt[1]<x && cnt[2]<x){
                cnt[1]++;
                cnt[2]++;
                share++;
            }else{
                return 0;
            }
        }else{
            if(cnt[0]<x && cnt[1]<x && cnt[2]<x){
                cnt[0]++;
                cnt[1]++;
                cnt[2]++;
                share++;
            }else{
                return 0;
            }
        }
    }
    if(share>x)return 0;
    return 1;
}

int bs(int l,int r){
    int mid;
    int ans = 200000;
    while(l<=r){
        mid = (l+r)>>1;
        if(judge(mid)){
            r=mid-1;
            ans = min(ans,mid);
        }else{
            l=mid+1;
        }
    }   
    return ans;
}

int main(){

    cin>>n;
    for(int i=0;i<3;i++){
        cin>>m[i];
    }
    sort(m,m+3);
    int sum = m[0]+m[1]+m[2];
    for(int i=0;i<n;i++){
        scanf("%d",&t[i]);
    }
    sort(t,t+n);
    if(t[n-1]>sum){
        cout<<-1<<endl;
    }else{
        int ans = bs(n/3,n);
        cout<<ans<<endl;
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值