难得补完一次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;
}
博主补完一次Div2后写题解,给出竞赛传送门。涵盖A - F六道题,A题用贪心算法;B题枚举答案;C题是数学题,倒推求解;D题是交互题,注意输出格式;E题求数组合在mod k下的情况;F题用记忆化搜索减少时间复杂度。
836

被折叠的 条评论
为什么被折叠?



