1. 程式人生 > >Codeforces Round #499 (Div. 2)

Codeforces Round #499 (Div. 2)

難得補完一次Div2,那麼過分弱雞一定要寫題解(guna)

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;
}