A 大家一起点外卖
链接:http://code.bupt.edu.cn/problem/p/437/
思路:水题,注意负数的情况,注意long long 就能过了。
code:
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#define INF 100000005
#define eps 1e-9
using namespace std;
const int MAX_N=500005;
const int MAX_M=2000005;
int a[MAX_N],n,m;
int ma,mb;
int used[MAX_M],flag;
int abc(int a)
{
if(a<0) return -a;
return a;
}
void solve()
{
flag=false;
ma=0;
mb=INF;
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
used[a[i]]++;
}
for(int i=0;i<n;i++){
if(m-a[i]<0) continue;
if(!used[m-a[i]]) continue;
if(m-a[i]==a[i]&&used[a[i]]<2) continue;
if((mb-ma)>(abc(m-a[i]-a[i]))){
mb=max(m-a[i],a[i]);
ma=min(m-a[i],a[i]);
flag=true;
}
}
if(flag==false){
printf("Sad\n");
return ;
}
printf("%d %d\n",ma,mb);
return ;
}
int main()
{
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
memset(used,0,sizeof(used));
solve();
}
return 0;
}
B 田田的公司
链接:http://code.bupt.edu.cn/problem/p/438/
思路:裸的并查集,比赛时候没有注意到long long 到最后也没过。
code:
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#define INF 100000005
#define eps 1e-9
using namespace std;
const int MAX_N=100005;
const int MAX_M=2000005;
int par[MAX_N];
int high[MAX_N];
long long value[MAX_N];
void init(int n)
{
for(int i=0;i<=n;i++){
par[i]=i;
value[i]=0;
}
}
int Find(int x)
{
if(par[x]==x) return x;
else return par[x]=Find(par[x]);
}
void unite(int x,int y)
{
x=Find(x);
y=Find(y);
if(x==y) return ;
if(value[x]<value[y]){
par[x]=y;
value[y]+=value[x];
}
else{
par[y]=x;
value[x]+=value[y];
}
}
bool same(int x,int y)
{
return Find(x)==Find(y);
}
int main()
{
int T,n,m,tt,a,b;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
init(n);
for(int i=1;i<=n;i++) scanf("%lld",&value[i]);
while(m--){
scanf("%d",&tt);
if(tt==1){
scanf("%d%d",&a,&b);
unite(a,b);
}
if(tt==2){
scanf("%d",&a);
printf("%lld\n",value[Find(a)]);
}
}
}
return 0;
}
C 崔逗逗的难题
链接:http://code.bupt.edu.cn/problem/p/439/
思路:公式都能推出来但是这道题题目卡精度,我的其他同学都能用double水过去,我无论换什么姿势用double都水不过去。
未ac code:
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#define INF 100000005
#define eps 1e-9
//#define Pi 3.1415926536
using namespace std;
const int MAX_N=100005;
const int MAX_M=2000005;
const int p=90000;
const double Pi=acos(-1.0);
int main()
{
double r;
while(~scanf("%lf",&r)){
double s1=(Pi/3.0+1-sqrt(3.0))*(r*r);
double s2=4.0*((Pi/12.0-1+sqrt(3.0)/2.0)*(r*r));
double s3=4.0*(r*r-(Pi/6.0)*(r*r)-(sqrt(3.0)/4.0)*(r*r));
printf("%.6lf %.6lf %.6lf\n",(Pi/3.0+1.0-sqrt(3.0))*r*r,4.0*((Pi/12.0-1.0+sqrt(3.0)/2.0)*r*r),4.0*(1.0-Pi/6.0-sqrt(3.0)/4.0)*r*r);
}
return 0;
}
D 崔逗逗给你信心
链接:http://code.bupt.edu.cn/problem/p/435/
思路: 我感觉这是一道比较好的题,多个步骤换换相扣。
(1)根据式子x^(2x)^(3x)可得,x^2x=3x => x^2x=x+2x。2乘以x相当于将x二进制表示的最高位上加1的位置上放一个1,所以想要使等式成立就必须,x的二进制表示不能有相邻的1,因为如果有相邻的1,则做加法的时候高位上会产生一个1,而异或的话原来是1的位置将全部变成零。
(2)根据第一步的结论,我们需要做的就是判断小于n的数中有多少个相邻位置上不含一的数。我们以a[n]表示1~n位的二进制数中有多少相邻位上没有一的数。可以得到一个斐波那契数列就是 a[n]=a[n-1]+a[n-2]。预处理出这个数列再将每个带待求的n处理成二进制 ,从最高位向最低位扫,对于每个二进制位为1的位i,如果其后面的位也是一就可以则res+=a[i]跳出;如果后面的位是0则res+=a[i-1],再继续判断其他位。
(3) 其中还有很多的细节地方,赛后我也是改了好久才过了这道题。
code:
#include <iostream>
#include <cstring>
#include <cstdlib>
#include<cstdio>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
#define INF 999999999
#define eps 1e-9
using namespace std;
const int MAX_M=200;
const int MAX_N=100005;
const int p=1000000009;
int a[100];
int bit[100];
int convert(long long n,int tt[])
{
long long d=1;
int cnt=0;
while(d<=n) d=d*2,cnt++;
d/=2;
for(int i=cnt;i>=1;i--){
tt[i]=n/d;
n%=d;
d/=2;
}
return cnt;
}
int main()
{
a[0]=1;
a[1]=2;
for(int i=2;i<=100;i++) a[i]=(a[i-1]+a[i-2])%p;
long long x;
int l,res;
bool flag=0;
while(~scanf("%lld",&x)){
bit[0]=res=flag=0;
l=convert(x,bit);
for(int i=l;i>=2;i--){
if(bit[i]&&bit[i-1]){
res=(res+a[i]-1)%p;
flag=1;
break;
}
if(bit[i]) res=(res+a[i-1])%p;
}
if(bit[1]&&!flag) res++;
if(x==1) res++;
else res++;
printf("%d\n",res);
}
}
E 焦级长搭积木
链接:http://code.bupt.edu.cn/problem/p/434/
思路:用dp的方法可以很快的求出来总步数,dp[i][j][k]=dp[i-k][j-1][k-1]+dp[i-k][j-1][k+1] 其中dp[i][j][k] 表示一个i个积木搭成j层最底层k个的总数量。
之后就是求第k个排序,在这个地方卡了一下一直想不到比较好的方法,去看了一下菊苣们的题解知道了,就是对于每个位置判断k和dp[n][h][m]的关系,前dp[n-m][h-1][m-1] 种序列对应的操作室将上一次层的数量-1,第dp[n-m][h-1][m-1]+1到dp[n-m][h-1][m+1]种序列对应的操作是上一层的数量+1,这样我们不断的更新跟新就能更新出第k种序列了。
code:
#include <iostream>
#include <cstring>
#include <cstdlib>
#include<cstdio>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
#define INF -1000000000
#define eps 1e-9
using namespace std;
const int MAX_N=545;
const int MAX_H=65;
const int MAX_M=20;
long long dp[MAX_N][MAX_H][MAX_M];
int N,M,H;
long long nn;
void solve()
{
memset(dp,0,sizeof(dp));
for(int i=1;i<=N;i++){
if(i<=10) dp[i][1][i]=1;
for(int j=2;j<=H;j++){
for(int k=1;k<=10;k++)
if(k<=i) dp[i][j][k]=dp[i-k][j-1][k-1]+dp[i-k][j-1][k+1];
}
}
printf("%lld\n",dp[N][H][M]);
}
void output(int N,int H,int M,long long k)
{
int a[H+1];
int n=N,h=H,m=M;
a[0]=m;
for(int i=1;i<H;i++){
if(k<=dp[n-m][h-1][m-1]){
a[i]=m-1;
n=n-m;
h--;
m--;
}
else{
k-=dp[n-m][h-1][m-1];
a[i]=m+1;
n=n-m;
h--;
m++;
}
}
for(int i=0;i<H;i++){
printf("%d",a[i]);
if(i!=H-1) printf(" ");
}
printf("\n");
}
int main()
{
while(~scanf("%d%d%d",&N,&H,&M)){
solve();
cin>>nn;
while(nn!=-1){
output(N,H,M,nn);
cin>>nn;
}
}
return 0;
}