2018CCPC吉林赛区(重现赛)

A The Fool 签到题 数论分块 数学题
B The World 时间处理问题 字符串
C Justice 思维题
E The Tower 计算几何 几何题
I Strength 贪心+田忌赛马 博弈论

A The Fool

数论分块(队友写的,所以没有解析)

# include <bits/stdc++.h>
using namespace std;

const int mod = 2;
int main(){
    int t;
    cin>>t;
    int k = 0;
    while(t--){
        LL n;
        cin>>n;
        LL ans = 0;
        for(LL l=1,r;l <= n; l = r + 1){
            r = n / (n / l);
            ans = (ans + (r - l + 1) * (n / l)) % mod;
        }
        printf("Case %d: ",++k);
        if(ans) printf("odd\n");
        else    printf("even\n");
    }
    return 0;
}

B The World

这个其实是一个水题,但是有一个坑点,我当时也没注意到wa了一次,后面学长提醒才注意到就是am只的是凌晨12点到中午的11:59:59,而从下午的12点开始就是pm了,一直到晚上的11:59:59。上述也为一天的具体时间。

 include <bits/stdc++.h>
using namespace std;

int main()
{
	int T;
	scanf("%d",&T);
	
	for(int i=1;i<=T;i++){
		int h;
		string a;
		string m;
		string d;
		string s1,s2;
		cin>>h;
		getchar();//独掉“:”
		cin>>m;
		cin>>a;
		if(a=="PM"){//转化为二十四小时制
			if(h!=12) h=h+12;//如果是12点的话,属于pm的只有中午12点,所以不要用转化,不太明白的可以看开头关于am,pm的解释
		} 
		if(a=="AM"){//如果是属于am的12点就是夜里凌晨转化为0防止混淆
			if(h==12) h=h-12;
		}
		cin>>s1;
		cin>>s2;
		int utc;
		if(s1=="Beijing") utc=h-8;//将现在的时间转化为utc标准时间
		if(s1=="Washington") utc=h+5;
		if(s1=="London") utc=h;
		if(s1=="Moscow") utc=h-3;
		
		if(s2=="Beijing") h=utc+8;//将utc时间再转化为当前时间
		if(s2=="Washington") h=utc-5;
		if(s2=="London") h=utc;
		if(s2=="Moscow") h=utc+3;
		
		if(h<0){//判断是昨天,今天还是明天
			h=h+24;
			d="Yesterday";
		}else if(h>=24){
			h=h-24;
			d="Tomorrow";
		}else{
			d="Today";
		}
		
		//判断是am还是pm,同时将时间转化为12小时制的
		if(h>=12&&h<24){//pm的转化,注意特判12
			if(h!=12) h=h-12;
			a="PM";
		}else if(h==0){//凌晨12点的特判
			h=12;
			a="AM";
		}else{
			a="AM";
		}
		cout<<"Case "<<i<<": "<<d<<" "<<h<<":"<<m<<" "<<a<<endl;
	}

	return 0;
}

C Justice

队友写的(所以还是没有解析,不要打我)

# include <bits/stdc++.h>
using namespace std;

const int maxn = 1e5 + 10;
bool vis[maxn];
int dp[maxn];
vector<int> dict[maxn];
inline void init(){
    memset(vis,0,sizeof vis);
    memset(dp,0,sizeof dp);
    for(int i = 0; i < maxn; ++i)
        dict[i].clear();
}
int main(){
    int t;
    cin>>t;
    int k = 0;
    while(t--){
        int n;
        cin>>n;
        init();
        LL tt;
        for(int i = 1; i <= n; ++i){
            tt;
            cin>>tt;
            if(tt < maxn){
                dp[tt]++;
                dict[tt].push_back(i);
            }
        }
        printf("Case %d: ",++k);

        for(int i = maxn - 1; i >= 2; --i){
            dp[i - 1] += dp[i] / 2;
        }
        if(dp[1] < 2){
            printf("NO\n");
            continue;
        }

        LL sum = 1;
        for(int i = 1; i <= n; ++i,sum <<= 1){
            if(sum <= dict[i].size()){
                for(int j = 0; j < sum; ++j){
                    vis[dict[i][j]] = 1;
                }
                break;
            }
            else{
                for(int j = 0; j < dict[i].size(); ++j){
                    vis[dict[i][j]] = 1;
                }
                sum -= dict[i].size();
            }
        }
        printf("YES\n");
        for(int i = 1; i <= n; ++i){
            printf("%d",vis[i] ? 1 : 0);
        }
        printf("\n");
    }
    return 0;
}

E The Tower

证明

# include <bits/stdc++.h>
using namespace std;

int main()
{
	int T;
	int ccase=0;
	scanf("%d",&T);
	
	while(T--){
		double r,h;
		double a,b,c;
		double x0,y0,z0,vx,vy,vz;
		double ans1=0.0,ans2=0.0,ans=1e18;
		
		scanf("%lf %lf",&r,&h);
		scanf("%lf %lf %lf",&x0,&y0,&z0);
		scanf("%lf %lf %lf",&vx,&vy,&vz);
		
		a=h*h*vx*vx+h*h*vy*vy-vz*vz*r*r;
		b=2*h*r*r*vz+2*h*h*x0*vx+2*h*h*y0*vy-2*z0*vz*r*r;
		c=-(h*h*(r*r-x0*x0-y0*y0)+r*r*z0*z0-2*h*r*r*z0);
		
		//cout<<"@@@@"<<a<<" "<<b<<" "<<c<<endl;
		ans1=(-b+sqrt(b*b-4*a*c))/(2.0*a);
		ans2=(-b-sqrt(b*b-4*a*c))/(2.0*a);
		
		//cout<<"####"<<ans1<<" "<<ans2<<endl;
		if(ans1>0){
			double tz=z0+ans1*vz;
			if(tz>=0&&tz<=h){
				ans=min(ans1,ans);
			}
		}
		
		if(ans2>0){
			double tz=z0+ans2*vz;
			if(tz>=0&&tz<=h){
				ans=min(ans2,ans);
			}
		}
		
		double t=-z0/vz;
		double tx=x0+vx*t,ty=y0+vy*t;
		if((tx*tx+ty*ty)<=r*r){
			ans=min(ans,t);
		}
		
		printf("Case %d: %.10f\n",++ccase,ans);
	}
	
	return 0;
 } 

I Strength

【思路】就是先对是否要用己方(假设我们是Alice 对方是Bob)的小怪物去处理对方的防御性的小怪物,处理掉的话,那么是为了剩下来的小怪物(除了和攻击性的打)能够产生全部的贡献(就是全部都是伤害),如果不处理是为了和攻击性的小怪物产生最大的差

对每一次查询,先判断是否能够全部都用小怪物打掉,如果能,那么就用最小的代价把防御性的对方的小怪物处理掉(因为防御性的不对结果产生贡献)然后剩下的相加减去对方攻击性的小怪物就是该种情况的最大伤害;那么不管是不是可以都把对方的小怪物处理掉,都要只对对方攻击性的小怪物贪心一次,就是用当前最大的去和对方最小的去打,那么两者之差的求和就是该种方法的最大的伤害(类似于田忌赛马)

# include <bits/stdc++.h>
using namespace std;

const int MAXN=1e6+100;
typedef long long LL;
LL a[MAXN];
int vis[MAXN]; 
pair<LL,LL> b[MAXN];
int main()
{
	int T;
	int ccase=0;
	scanf("%d",&T);
	
	while(T--){
		int n,m;
		LL ans1=0,ans2=0;
		LL ans=0;
		scanf("%d %d",&n,&m);
		for(int i=1;i<=max(n,m);i++) a[i]=0,vis[i]=0,b[i].first=0,b[i].second=0;
		for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
		for(int i=1;i<=m;i++) scanf("%lld",&b[i].first);
		for(int i=1;i<=m;i++) scanf("%lld",&b[i].second);
		
		sort(a+1,a+n+1);
		sort(b+1,b+m+1);
		
		int flag1=1;//判断是否是可以全部都过 
		for(int i=n,j=m;i>=1&&j>=1;i--,j--){
			if(a[i]<b[j].first){
				flag1=0;
				break;
			}
		}
		
		if(flag1){//如果可以全部都过
			for(int i=1,j=1;i<=n&&j<=m;){//先用最小的代价处理掉防御性的小怪物 
				if(b[j].second==0){
					j++;
				}else{
					if(a[i]>b[j].first){
						vis[i]=1;//标记用来处理防御性的小怪物 
						i++,j++;
					}else{
						i++;
					}
				}
			}
			//for(int i=1;i<=n;i++) cout<<"%%%%"<<vis[i]<<endl;
			LL sum=0,sum1=0;
			for(int i=1;i<=n;i++){
				if(vis[i]==0){
					sum+=a[i];
				}
			} 
			for(int i=1;i<=m;i++){
				if(b[i].second==0){
					sum1+=b[i].first;
				}
			}
			//cout<<"@@@"<<sum<<" "<<sum1<<endl;
			ans1=sum-sum1;
		}
		//如果不可以全部都过,那么就对只有攻击性的贪心 
		int k=1;
		LL sum2=0;
		for(int i=n;i>=1&&k<=m;){
			if(b[k].second==0){
				if(a[i]>b[k].first){
					sum2+=(a[i]-b[k].first);
					i--;
				}else{
					break;
				}
			}
			k++;	
		}
		ans2=sum2;
		ans=max(ans1,ans2);
		//cout<<"@@@"<<ans1<<" "<<ans2<<endl;
		printf("Case %d: %lld\n",++ccase,ans);
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值