和队友打模拟赛遗憾的打铁了,在这里总结一下题,还是太菜了。。
题目难度由易到难的顺序讲解。
C题队友wa了4发后A了,一开始题意都不太理解,但实际上就是求N个数组成的所有数中的就行了。仔细想想其实题目不是很难理解。
代码如下:
#include<iostream>
#include<stdio.h>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int num[45];
ll dp[45][40005];
int N;
double P;
void solve()
{
memset(dp,0,sizeof(dp));
dp[0][0]=1;
for(int i=1; i<=N; i++)
{
for(int j=0;j<=40000;j++)if(dp[i-1][j])
{
dp[i][j+num[i]]+=dp[i-1][j];
dp[i][j]+=dp[i-1][j];
}
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d %lf",&N,&P);
for(int i=1; i<=N; i++)
scanf("%d",&num[i]);
solve();
long long choose=ceil(((1LL<<N)-1)*P);
for(int i=1;i<=40000;i++)
{
if(choose<=0)
{
cout<<i-1<<endl;
break;
}
choose-=dp[N][i];
}
}
}
I题思路:一开始博主有一个思路,上去写了后发现事情并不简单,在判断以哪个点结束的串是否可行的时候出现了问题。看了题解之后瞬间懂了。当时也写了hash,但没想到可以这样遍历串:首先枚举起点i,算这个串之后并不是枚举i+1,而是把该串的开头的L串删掉,再从末尾加上一个L串,然后在判断。
所以枚举一开始的起点就是从0到L-1即可,后面跳的过程判断是否可行用map的大小即可。
代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int maxn=100005;
const ull hashsize=19560817;
ull p[maxn+10];
ull S[maxn+10];
int L,M;
string a;
void init()
{
int len=a.size();
for(int i=1;i<=len;i++)
S[i]=S[i-1]*hashsize+a[i-1];
}
ull HS(int l,int r)
{
if(l==r)return a[l];
l++,r++;
return S[r]-S[l-1]*p[r-l+1];
}
map<ull,int>themap;
void solve()
{
int ans=0;
int len=a.size();
for(int i=0;i<L&&i+M*L-1<len;i++)
{
int now=0;
themap.clear();
while(now<M)
{
themap[HS(i+now*L,i+now*L+L-1)]++;
now++;
}
if(themap.size()==M)
ans++;
while(i+now*L+L-1<len)
{
ull temp=HS(i+now*L,i+now*L+L-1);
themap[temp]++;
temp=HS(i+L*(now-M),i+L*(now-M)+L-1);
themap[temp]--;
if(themap[temp]==0)
themap.erase(temp);
if(themap.size()==M)
ans++;
now++;
}
}
cout<<ans<<endl;
}
int main()
{
p[0]=1;
for(int i=1;i<=maxn;i++)
p[i]=p[i-1]*hashsize;
while(~scanf("%d %d",&M,&L))
{
cin>>a;
init();
solve();
}
}
G题思路:G题做不出来的就是菜啊。。。一道模板题,这题没有解题思路,就是套模板即可,2维线段树区间查询单点修改求最值。
#include<iostream>
#include<algorithm>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define MAXN 805 ///大小
struct seg /// 单点修改,区间查询极值模板
{
int xL, xR, yL, yR, val; /// 查询时xL,xR,yL,yR为边界,修改时(xL,yL)为修改点val为值
int maxv, minv;
int Max[MAXN << 2][MAXN << 2], Min[MAXN << 2][MAXN << 2];
int N, mat[MAXN][MAXN];
void init()
{
maxv = -(1 << 30);
minv = 1 << 30;
}
void PushUp(int xrt, int rt)
{
Max[xrt][rt] = max(Max[xrt][rt << 1], Max[xrt][rt << 1 | 1]);
Min[xrt][rt] = min(Min[xrt][rt << 1], Min[xrt][rt << 1 | 1]);
}
void BuildY(int xrt, int x, int l, int r, int rt)
{
int m;
if (l == r)
{
if (x != -1)Max[xrt][rt] = Min[xrt][rt] = mat[x][l];
else
{
Max[xrt][rt] = max(Max[xrt << 1][rt], Max[xrt << 1 | 1][rt]);
Min[xrt][rt] = min(Min[xrt << 1][rt], Min[xrt << 1 | 1][rt]);
}
return;
}
m = l + r >> 1;
BuildY(xrt, x, lson);
BuildY(xrt, x, rson);
PushUp(xrt, rt);
}
void BuildX(int l, int r, int rt)
{
int m;
if (l == r)
{
BuildY(rt, l, 1, N, 1);
return;
}
m = l + r >> 1;
BuildX(lson);
BuildX(rson);
BuildY(rt, -1, 1, N, 1);
}
void UpdateY(int xrt, int x, int l, int r, int rt)
{
int m;
if (l == r)
{
if (x != -1)Max[xrt][rt] = Min[xrt][rt] = val;
else
{
Max[xrt][rt] = max(Max[xrt << 1][rt], Max[xrt << 1 | 1][rt]);
Min[xrt][rt] = min(Min[xrt << 1][rt], Min[xrt << 1 | 1][rt]);
}
return;
}
m = (l + r) >> 1;
if (yL <= m)UpdateY(xrt, x, lson);
else UpdateY(xrt, x, rson);
PushUp(xrt, rt);
}
void UpdateX(int l, int r, int rt)
{
int m;
if (l == r)
{
UpdateY(rt, l, 1, N, 1);
return;
}
m = (l + r) >> 1;
if (xL <= m)UpdateX(lson);
else UpdateX(rson);
UpdateY(rt, -1, 1, N, 1);
}
void QueryY(int xrt, int l, int r, int rt)
{
int m;
if (yL <= l&&yR >= r)
{
minv = min(minv, Min[xrt][rt]);
maxv = max(maxv, Max[xrt][rt]);
return;
}
m = (l + r) >> 1;
if (yL <= m)QueryY(xrt, lson);
if (yR>m)QueryY(xrt, rson);
}
void QueryX(int l, int r, int rt)
{
int m;
if (xL <= l&&xR >= r)
{
QueryY(rt, 1, N, 1);
return;
}
m = (l + r) >> 1;
if (xL <= m)QueryX(lson);
if (xR>m)QueryX(rson);
}
}Seg;
int main()
{
int T;
scanf("%d", &T);
for (int cas = 1;cas <= T;cas++)
{
scanf("%d", &Seg.N);
for (int i = 1;i <= Seg.N;i++)
for (int j = 1;j <= Seg.N;j++)
scanf("%d", &Seg.mat[i][j]);
Seg.BuildX(1, Seg.N, 1);
int Q;
scanf("%d", &Q);
printf("Case #%d:\n", cas);
int L, x, y;
while (Q--)
{
scanf("%d %d %d", &x, &y, &L);
int length = (L - 1) / 2;
Seg.xL = max(1, x - length);
Seg.xR = min(Seg.N, x + length);
Seg.yL = max(1, y - length);
Seg.yR = min(Seg.N, y + length);
Seg.init();
Seg.QueryX(1, Seg.N, 1);
int themax = Seg.maxv;
int themin = Seg.minv;
printf("%d\n", (themax + themin) / 2);
Seg.val = (themax + themin) / 2;
Seg.xL = x;
Seg.yL = y;
Seg.UpdateX(1, Seg.N, 1);
}
}
}
B题思路:比赛的时候知道了一个公式
θn=θn−1+θn−2
然后发现所有的幂都可以写成θ^2的表达方式,然后发现系数成斐波那契数列,结果越想越远,写了一个递归的方法,过后突然发现系数的问题还是不是特别好解决。
看了题解后突然发现还有一个公式:
2∗θn=θn+1+θn−2
,然后可以把一个数”稀释”到它的两边,不断的将系数变小,再不断的用第一个公式将连续的两个1合并到一个1就行了。
#include<iostream>
#include<stdio.h>
#include<cstring>
using namespace std;
int num[105];
int main()
{
int N;
while(~scanf("%d",&N))
{
memset(num,0,sizeof(num));
num[50]=N;
while(1)
{
bool flag=true;
for(int i=0; i<100; i++)
{
if(num[i]>1)
{
num[i+1]+=num[i]/2;
num[i-2]+=num[i]/2;
num[i]%=2;
flag=false;
}
}
for(int i=0; i<100; i++)
{
if(num[i]>=1&&num[i+1]>=1)
{
int temp=min(num[i],num[i+1]);
num[i]-=temp;
num[i+1]-=temp;
num[i+2]+=temp;
flag=false;
}
}
if(flag)
break;
}
int begin,end=50;
for(int i=100; i>=50; i--)
if(num[i]==1)
{
begin=i;
break;
}
for(int i=0; i<=49; i++)
if(num[i]==1)
{
end=i;
break;
}
for(int i=begin; i>=50; i--)
{
if(num[i]==1)
printf("1");
else printf("0");
}
if(end!=50)
{
printf(".");
for(int i=49;i>=end;i--)
{
if(num[i]==1)
printf("1");
else printf("0");
}
}
printf("\n");
}
return 0;
}
总结:题目都是好题,可惜不会做,做完之后感觉丰满了很多。继续努力吧。