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