2017.2.19 loli测试

来源:互联网 发布:非负矩阵倍增更新法则 编辑:程序博客网 时间:2024/06/11 10:02


去掉失误,这应该是我独自A的第一个省选题、、

发代码纪念一下:


#include<iostream>
#include<cstdio>
using namespace std;
#include<algorithm>
#include<map>
map<long long  ,long long>hehe;
map<long long ,bool>you;
long long n,len,i,j,k,x,lin,m,wen;
struct tree 
{
long long  zhi,wei;
}dian[99999999];
long long gcd(long long a,long long b)
{
if(!b)return a;
gcd(b,a%b);
}
bool cmp(tree a,tree b)
{
return a.wei>b.wei;
}
int main()
{
scanf("%lld",&n);
len=0;
for(i=1;i<=n;i++)
{   
scanf("%lld",&x);
if(you[x]==0)
{
dian[++len].wei=i;
dian[len].zhi=x;
}
// cout<<len<<endl;
for(j=1;j<=len;j++)
{   you[dian[j].zhi]=0;
dian[j].zhi=gcd(x,dian[j].zhi); 
}
lin=len;
// cout<<lin<<endl;
len=0;
for(j=1;j<=lin;j++)
{   
bool youyou=0;
for(k=1;k<=len;k++)
{
if(dian[k].zhi==dian[j].zhi)
{
youyou=1;
dian[k].wei=min(dian[k].wei,dian[j].wei);
}
}
if(!youyou)
{
dian[++len].wei=dian[j].wei;
dian[len].zhi=dian[j].zhi;
}
}
      //cout<<len;
sort(dian+1,dian+1+len,cmp);
//  for(j=1;j<=len;j++)
//   cout<<dian[j].wei;
lin=i+1;
for(j=1;j<=len;j++)
{   
you[dian[j].zhi]=1;
hehe[dian[j].zhi]+=(lin-dian[j].wei);
lin=dian[j].wei;
// cout<<dian[j].zhi<<"  "<<hehe[dian[j].zhi]<<endl;
}
}
scanf("%lld",&m);
for(i=1;i<=m;i++)
{
scanf("%lld",&wen);
printf("%lld\n",hehe[wen]);
}
}        、、、、、、、、、







此题其实是挺裸的网络流,然而对位运算和网络流原理、模型了解不深的我来说打了个贪心,然而第二问和第三问看出了网络流却不知位运算的性质、、、

记住:位运算各个数位互不影响!!!

所以对于第一问可以这样建图:


粉边代表人一开始有的每种糖果数、红边代表流向需要这种糖的小伙伴、紫边代表这个小伙伴多出,可用于交换的糖果数、蓝边代表流向答案的种数。

利用最大流中终点流量最大的原理,可求出最大种类数。


对于第二、三问。


1表示这一位为1的点,0表示这一位为0的点,x表示需要求值的点。

根据最大流=最小割的原理,跑完最大流时,dfs求割。


它就被分成了选0的和选1的两部分。

和s在一个集合里的选1,和t在一个集合里的选0.

同时让选1的尽可能少(实际上从s直接dfs就行了)

就同时求出了第二问和第三问。









0 0