Codeforces Round #499 (Div. 2)

难得补完一次Div2,那么过分弱鸡一定要写题解(guna)

传送门:http://codeforces.com/contest/1011

A题

贪心,排了序从头开始找,满足条件能找到n个数字就OJBK

【因为如果答案里没包含排序后的第一个,那肯定能把答案里的第一个位置的数值换成最小的那个,这样的答案更小,所以正解的第一个stage一定是最小那个开始】

#include<bits/stdc++.h>
using namespace std;
int n,m;
char st[50];

int main(){
	scanf("%d%d",&n,&m);
	scanf("%s",st);
	sort(st,st+strlen(st));
	
	int cnt=0,cntn=0,ans=0;
	ans=st[0];cnt=1;cntn=st[0];
	
	for (int i=1;i<n;i++)
	{ if (cnt==m)break;
	  if (st[i]-cntn>=2){
	     ans+=st[i];cnt++;cntn=st[i];
	  }
	}
	if (cnt!=m)printf("-1\n");
	  else printf("%d\n",ans-'a'*m+m);
	 
	return 0;
}

B题

枚举答案,因为理论上坚持的天数最多为100(所有的食物都是同一类,m/n 最大为100)所以就不二分了

从大到小枚举答案,统计每种粮食够多少人吃,统计的数目>=n时就找到答案了

#include<bits/stdc++.h>
using namespace std;
map<int,int>food;
int n,m,lin;

int check(int ans)
{  int cnt=0;
   if (ans==0)return 1;
   for (map<int,int>::iterator it=food.begin();it!=food.end();it++)
       cnt+=it->second/ans;
      	
    if (cnt>=n)return 1;
	return 0;	  
}

int main()
{   scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++)
      {scanf("%d",&lin);
       if (food.find(lin)==food.end())food[lin]=1;
           else food[lin]++;
	  }
	
	for (int i=m/n;i>=0;i--)
	  if (check(i)){printf("%d\n",i);break;}
	return 0;
}

C题

数学题,设起飞或着陆后飞机重m,过程中消耗的燃油质量为y 那么 m+y=y*a[i](或b[i]),y=m/(a[i]-1)

然后从火星到地球一路倒着推回去就行了,因为分母里有a[i]-1,所以输入时看下有没有a[i]=1的,如果有就无解

#include<bits/stdc++.h>
using namespace std;
int n,w,a[1009],b[1009];

int main()
{  scanf("%d",&n);
   scanf("%d",&w);
   for (int i=1;i<=n;i++)
    { scanf("%d",&a[i]);
	 if (a[i]==1){printf("-1\n");return 0;}}
   for (int i=1;i<=n;i++)
    { scanf("%d",&b[i]);
	 if (b[i]==1){printf("-1\n");return 0;}}
   
   double weight=double(w);
   weight+=weight/(double(b[1])-1.0);
   weight+=weight/(double(a[n])-1.0);
   
   for (int i=n;i>1;i--)
   {  weight+=weight/(double(b[i]-1.0));
      //从上个星球起飞所以是i-1  细节要注意 
      weight+=weight/(double(a[i-1]-1.0));
   }
   
   weight-=double(w);
   printf("%.10lf\n",weight);
   return 0;
}

D题

交互题。。。。开始前半小时看了下,只要注意每次输出后要有换行符以及输出语句后要加个fflush(stdout);语句就行了(c++)

首先问n个1,如果回复为0那就直接退出程序就OK了,不然返回的值就是说谎序列d(因为要猜的数不可能比1小)

之后二分就完了

#include<bits/stdc++.h>
using namespace std;
int f[33],m,n,ans;

int main(){
	scanf("%d%d",&m,&n);
	for (int i=1;i<=n;i++)
	{  printf("1\n");
	   fflush(stdout);
	   scanf("%d",&ans);	
	   if (ans==0) return 0;
	   f[i]=ans;
	}
	
    int l = 1, r = m ,mid;
    int cnt=0;
    while (l != r) {
        int mid = (l + r + 1) / 2;
        printf("%d\n", mid);
        fflush(stdout);

        cnt++; if (cnt>n)cnt-=n;
        scanf("%d",&ans);
        if (ans==0)return 0;
        
        if (ans*f[cnt]== -1)
            r = mid - 1;
        else
            l = mid;
            
    }
    
	return 0;
}

E题

题意给你n个数,可以自由组合看能搞出哪些数(在mod k的情况下)

先求这些数集体的最大公约数,之后所有的这些数的组合肯定是最大公约数的某个倍数,乱搞Orz

这个学到了

#include<bits/stdc++.h>
#define ll long long

using namespace std;
int lin,n,k,g;
set<ll>ans;

ll gcd(ll a,ll b){return a!=0?gcd(b%a,a):b;} 

int main()
{  scanf("%d%d",&n,&k);
   for (int i=1;i<=n;i++)
   {scanf("%d",&lin);
    if(i==1)g=lin%k;
    else g=gcd(g,lin%k);
   }
  
   
   for (int i=1;i<=1000000;i++)
    ans.insert((ll)i*g%k);
    
    printf("%d\n",ans.size());
    for (set<ll>::iterator it=ans.begin();it!=ans.end();it++)
     if (it==ans.begin())printf("%d",*it);
       else printf(" %d",*it);
	
	return 0;
} 

 

F题

记忆化搜索,每个树节点记录一个change值,=0意味着这个点上的值变了对output没影响,=1有影响,=-1表示初值还没求

搜索的时候对于点i,如果已知change的值,那就直接能算output,不然看该改变对父节点值有没有影响,如果没有那么该点的change值就为0,不然再看父节点,父节点已知change值就可以判断output,否则再判断父节点值改变能不能改变父父节点的值。。。。。。

就这样搜下去

通过记录change的值来减少时间复杂度

 

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

struct node{
	int val;
	int l,r,f,change;
	char t;
	node(){
		val=l=r=f=-1;
		t='+';
		change=-1;
	}
	
}tree[1000009];
int n,lin,a[1000009];

//最开始用来求初始状态每个节点的值
int qiu(int wei)
{   
    if (tree[wei].val!=-1)return tree[wei].val;

    int l=tree[wei].l,r=tree[wei].r;    
    if (tree[wei].t=='N') 
	   tree[wei].val=qiu(l)^1;
	else
	if (tree[wei].t=='A')
	   tree[wei].val=qiu(l)&qiu(r);   
	else
    if (tree[wei].t=='O')
       tree[wei].val=qiu(l)|qiu(r);  
    else
    if (tree[wei].t=='X')
       tree[wei].val=qiu(l)^qiu(r); 
	
	return tree[wei].val;
}

//返回wei节点的change值
int chu(int wei)
{   if (tree[wei].change!=-1)return tree[wei].change;
 
    
    
    int ben=tree[wei].val^1,lin;
    int fa=tree[wei].f;  
    int fv=tree[fa].val;
    
	if (tree[fa].t=='N'){tree[wei].change=chu(fa); return tree[wei].change;}
	
    if (tree[fa].l==wei)
	  lin=tree[tree[fa].r].val;
	else    
	  lin=tree[tree[fa].l].val;
	
	
	if (tree[fa].t=='A')
	    {  
	       if ((ben&lin)==fv){tree[wei].change=0; return tree[wei].change;}
		}
	else
    if (tree[fa].t=='O')
        { 
	       if ((ben|lin)==fv){tree[wei].change=0; return tree[wei].change;}	     
		}
    else
    if (tree[fa].t=='X')
         { 
	       if ((ben^lin)==fv){tree[wei].change=0; return tree[wei].change;}		     
		}
	

    tree[wei].change=chu(fa); return tree[wei].change;
	
	
}
char st[10];

int main(){
	scanf("%d",&n);a[0]=0;
	for (int i=1;i<=n;i++){
	 scanf("%s %d",st,&lin);tree[i].t=st[0];
	    
	   if (st[0]!='I'&&st[0]!='N'){
	        tree[i].l=lin;scanf("%d",&tree[i].r);
			tree[tree[i].l].f=i;
			tree[tree[i].r].f=i;
			}
	       else if (st[0]=='I') {tree[i].val=lin;a[0]++;a[a[0]]=i;}
	          else {
	          	  tree[i].l=lin;
	          	  tree[lin].f=i;
			  }

	   }
	  
	  qiu(1);tree[1].change=1;
	  for (int i=1;i<=a[0];i++)
	  { 
	    if (chu(a[i]))printf("%d",tree[1].val^1);
	           else printf("%d",tree[1].val);
	  }
	   
	
	
	return 0;
} 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值