B Coffee Chicken
题意
定义一个字符串的斐波那契数列,求从第k位开始的后面十个字符。
分析
- 把第n项求出来是不可能的。
- 斐波那契数列的增长是很快的,而且由于题目保证\(k<=min(|S(n)|,10^{12})\),且只输出十个字符,因此其实只有前几十项是有用的。
- 把前面几十项的长度和字符串预处理出来,然后分治输出即可。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int T,n;
ll k,l[65];
string s[25];
void solve(int n,ll k,ll num){
if(n<=20){
for(int i=k-1,j=0;i<l[n] && j<num;i++,j++){
printf("%c",s[n][i]);
}
return;
}
if(k+num<=l[n-2]){
solve(n-2,k,num);
}else if(k>l[n-2]){
solve(n-1,k-l[n-2],num);
}else{
solve(n-2,k,l[n-2]-k+1);
solve(n-1,1,num-(l[n-2]-k+1));
}
}
int main(){
// freopen("in.txt","r",stdin);
l[1]=6;
l[2]=7;
s[1]="COFFEE";
s[2]="CHICKEN";
for(int i=3;i<=60;i++){
l[i]=l[i-2]+l[i-1];
}
for(int i=3;i<=20;i++){
s[i]=s[i-2]+s[i-1];
}
scanf("%d",&T);
while(T--){
scanf("%d%lld",&n,&k);
n=min(n,60);
solve(n,k,10);
printf("\n");
}
return 0;
}
D Han Xin and His Troops
题意
拓展中国剩余定理。
分析
不会数学,负责帮队友写了个Java大数版本。
代码
import java.io.*;
import java.math.BigInteger;
import java.util.Scanner;
public class Main {
static BigInteger[] b=new BigInteger[150];
static BigInteger[] a=new BigInteger[150];
static int n;
static BigInteger m;
public static BigInteger exgcd(BigInteger a,BigInteger b,BigInteger[] x,BigInteger[] y){
if(a.compareTo(BigInteger.ZERO)==0 && b.compareTo(BigInteger.ZERO)==0){
return new BigInteger("-1");
}
if(b.compareTo(BigInteger.ZERO)==0){
x[0]= BigInteger.ONE;
y[0]=BigInteger.ZERO;
return a;
}
BigInteger d=exgcd(b,a.mod(b),y,x);
y[0]=y[0].subtract(a.divide(b).multiply(x[0]));
return d;
}
static BigInteger excrt(){
BigInteger[] x=new BigInteger[2];
BigInteger[] y=new BigInteger[2];
BigInteger M=b[1];
BigInteger ans=a[1];
for(int i=2;i<=n;i++){
BigInteger ai=M,bi=b[i],ci=(a[i].subtract(ans.mod(bi)).add(bi)).mod(bi);
BigInteger gcd=exgcd(ai,bi,x,y);
BigInteger bg=bi.divide(gcd);
if(ci.mod(gcd).compareTo(BigInteger.ZERO)!=0){
return new BigInteger("-1");
}
x[0]=x[0].multiply(ci.divide(gcd)).mod(bg);
ans=ans.add(x[0].multiply(M));
M=M.multiply(bg);
ans=(ans.mod(M).add(M)).mod(M);
}
return (ans.mod(M).add(M)).mod(M);
}
public static void main(String[] args) {
Scanner cin=new Scanner(System.in);
n=cin.nextInt();
m=cin.nextBigInteger();
for(int i=1;i<=n;i++){
b[i]=cin.nextBigInteger();
a[i]=cin.nextBigInteger();
}
BigInteger ans=excrt();
if(ans.compareTo(BigInteger.valueOf(-1))==0){
System.out.println("he was definitely lying");
}else if(ans.compareTo(m)>0){
System.out.println("he was probably lying");
}else{
System.out.println(ans);
}
}
}
F Popping Balloons
题意
在一个二维平面有一些气球,横着打三枪竖着打三枪,要使打到的气球数最多。
分析
- 首先肯定是行列肯定是枚举一个,维护另一个,这里我们考虑枚举列,然后维护行打三枪的最大值。
- 考虑到列的影响,行的最值需要用线段树来维护,我们定义行\(i\)的值\(v[i]\)表示打了\(i,i+r,i+2*r\)三枪的最大值,那么枚举打了第\(j,j+r,j+2*r\)列时,这些列上对应的行的气球就被列的打掉,所以对行的贡献就没了。
- 因此对于枚举的列的每个行\(k\),将\(k,k-r,k-2*r\)的\(v[k]\)贡献减去即可。
代码
#include <bits/stdc++.h>
using namespace std;
#define ls i<<1
#define rs i<<1|1
#define mid (l+r)/2
const int N=1e5+50;
const int MAX=1e5+1;
int n,R,x,y;
vector<int> g[N];
int h[N],s[N];
int mx[N*4];
void pushup(int i){
mx[i]=max(mx[ls],mx[rs]);
}
void build(int i,int l,int r){
if(l==r){
mx[i]=s[l];
if(l+R<=MAX){
mx[i]+=s[l+R];
}
if(l+2*R<=MAX){
mx[i]+=s[l+2*R];
}
return;
}
build(ls,l,mid);
build(rs,mid+1,r);
pushup(i);
}
void update(int i,int l,int r,int p,int v){
if(l==r && l==p){
mx[i]+=v;
return;
}
if(p<=mid){
update(ls,l,mid,p,v);
}else{
update(rs,mid+1,r,p,v);
}
pushup(i);
}
int main(){
// freopen("in.txt","r",stdin);
scanf("%d%d",&n,&R);
for(int i=0;i<n;i++){
scanf("%d%d",&x,&y);
x++;
y++;
h[x]++;
s[y]++;
g[x].push_back(y);
}
int ans=0;
build(1,1,MAX);
for(int i=1;i<=MAX;i++){
int tmp=h[i];
int siz=g[i].size();
for(int j=0;j<siz;j++){
int v=g[i][j];
update(1,1,MAX,v,-1);
if(v-R>=1){
update(1,1,MAX,v-R,-1);
}
if(v-2*R>=1){
update(1,1,MAX,v-2*R,-1);
}
}
if(i+R<=MAX){
tmp+=h[i+R];
siz=g[i+R].size();
for(int j=0;j<siz;j++){
int v=g[i+R][j];
update(1,1,MAX,v,-1);
if(v-R>=1){
update(1,1,MAX,v-R,-1);
}
if(v-2*R>=1){
update(1,1,MAX,v-2*R,-1);
}
}
}
if(i+2*R<=MAX){
tmp+=h[i+2*R];
siz=g[i+2*R].size();
for(int j=0;j<siz;j++){
int v=g[i+2*R][j];
update(1,1,MAX,v,-1);
if(v-R>=1){
update(1,1,MAX,v-R,-1);
}
if(v-2*R>=1){
update(1,1,MAX,v-2*R,-1);
}
}
}
ans=max(ans,tmp+mx[1]);
siz=g[i].size();
for(int j=0;j<siz;j++){
int v=g[i][j];
update(1,1,MAX,v,1);
if(v-R>=1){
update(1,1,MAX,v-R,1);
}
if(v-2*R>=1){
update(1,1,MAX,v-2*R,1);
}
}
if(i+R<=MAX){
siz=g[i+R].size();
for(int j=0;j<siz;j++){
int v=g[i+R][j];
update(1,1,MAX,v,1);
if(v-R>=1){
update(1,1,MAX,v-R,1);
}
if(v-2*R>=1){
update(1,1,MAX,v-2*R,1);
}
}
}
if(i+2*R<=MAX){
siz=g[i+2*R].size();
for(int j=0;j<siz;j++){
int v=g[i+2*R][j];
update(1,1,MAX,v,1);
if(v-R>=1){
update(1,1,MAX,v-R,1);
}
if(v-2*R>=1){
update(1,1,MAX,v-2*R,1);
}
}
}
}
printf("%d\n",ans);
return 0;
}
H Stammering Chemists
题意
给一个6个点的树,判断属于题目中的哪一种。
分析
根据度数判断即可。
代码
#include <bits/stdc++.h>
using namespace std;
int T,u,v,ind[10],cnt[10];
vector<int> g[10];
int main(){
// freopen("in.txt","r",stdin);
scanf("%d",&T);
while(T--){
memset(ind,0,sizeof(ind));
memset(cnt,0,sizeof(cnt));
for(int i=1;i<=6;i++){
g[i].clear();
}
for(int i=0;i<5;i++){
scanf("%d%d",&u,&v);
ind[u]++;
ind[v]++;
g[u].push_back(v);
g[v].push_back(u);
}
for(int i=1;i<=6;i++){
cnt[ind[i]]++;
}
if(cnt[2]==4 && cnt[1]==2){
printf("n-hexane\n");
}else if(cnt[4]>0){
printf("2,2-dimethylbutane\n");
}else if(cnt[3]==2 && cnt[1]==4){
printf("2,3-dimethylbutane\n");
}else{
int rt=0;
for(int i=1;i<=6;i++){
if(ind[i]==3){
rt=i;
break;
}
}
int a[3]={0};
for(auto v:g[rt]){
a[ind[v]]++;
}
if(a[1]==1 && a[2]==2){
printf("3-methylpentane\n");
}else{
printf("2-methylpentane\n");
}
}
}
return 0;
}