杭电多校补提集
- Calculus
题目描述
因为对于单个函数来说,都要保证求和是收敛的。那么显然常熟求和不收敛,C/x可以提出C,就是经典求和,记结论是发散的,其他同样提出C发现是发散的,所以系数C必须是0.对于最后一个函数,因为规定C是0到1e9的整数,所以C只能是0才能求和收敛。那么只需要判断所有系数是否为0就做完了。
#include<bits/stdc++.h>
using namespace std;
int t,n;char s[110];
int main(){
scanf("%d",&t);
while(t--){
scanf("%s",s+1);
n=strlen(s+1);
bool flag=1;
for(int i=1;i<=n;i++){
if(s[i]>'0'&&s[i]<='9'){
flag=0;break;
}
}
if(flag) printf("YES\n");
else printf("NO\n");
}
return 0;
}
- License Plate Recognition
题目描述
大致思路就是,出了“川”和“鄂”,其他的所有汉字和字母都是连续的,也就是说我们只需要找到两个完全没有#的列,他们中间夹的就是一个字母或者汉字。上面两种不连续的汉字是特例,可以通过特判解决。
#include<bits/stdc++.h>
using namespace std;
char s[31][110];
int t;int a[110],cnt;
int main(){
scanf("%d",&t);
for(int k=1;k<=t;k++){
printf("Case #%d:\n",k);cnt=0;
for(int i=1;i<=30;i++) scanf("%s",s[i]+1);
int l,r,tmp=0,lef;
for(int j=1;j<=100;j++){
bool flag=1;
for(int i=1;i<=30;i++){
if(s[i][j]=='#') flag=0;
}
if(flag){
a[++cnt]=j;
}
}
//for(int i=1;i<=cnt;i++) printf("%d ",a[i]);
//cout<<endl;
for(int i=1;i<=cnt;i++){
if(a[i+1]-a[i]==4&&a[i+5]-a[i+4]==2&&a[i+10]-a[i+9]==2){
printf("%d %d\n",a[i]+1,a[i+10]-1);i=i+10;
}else if(a[i+1]-a[i]==10&&a[i+2]-a[i+1]==6){
printf("%d %d\n",a[i]+1,a[i+2]-1);i=i+2;
}else if(a[i+1]-a[i]>1){
printf("%d %d\n",a[i]+1,a[i+1]-1);
}
}
for(int i=1;i<=cnt;i++) a[i]=0;
}
return 0;
}
3.Kanade Loves Maze Designing
n很小,点权也不大。直接n方跑n遍,dfs+回溯即可。需要注意的是奇奇怪怪的输入形式以及输出格式。
#include<bits/stdc++.h>
using namespace std;
const int p1=1e9+7;
const int p2=1e9+9;
const int N=2e3+10;
int t,n,tot,lin[N],ver[N*2],Next[N*2],num[N],ans[N],v[N];
void add(int x,int y){
ver[++tot]=y;Next[tot]=lin[x];lin[x]=tot;
}
void dfs(int x,int fa,int now){
num[v[x]]++;
for(int i=lin[x];i;i=Next[i]){
int y=ver[i];
if(y==fa) continue;
if(!num[v[y]]) ans[y]=now+1;
else ans[y]=now;
dfs(y,x,ans[y]);
}
num[v[x]]--;
}
int main(){
scanf("%d",&t);
while(t--){
tot=0;
memset(lin,0,sizeof(lin));
scanf("%d",&n);
for(int i=1;i<n;i++){
int x,y;scanf("%d",&x);
add(x,i+1);add(i+1,x);
}
for(int i=1;i<=n;i++){
scanf("%d",&v[i]);
}
for(int i=1;i<=n;i++){
dfs(i,0,1);
ans[i]=1;
int tmp1=1,tmp2=1;int sum1=0,sum2=0;
for(int j=1;j<=n;j++){
sum1=(sum1+1LL*tmp1*ans[j]%p1)%p1;
sum2=(sum2+1LL*tmp2*ans[j]%p2)%p2;
tmp1=1LL*tmp1*19560929%p1;
tmp2=1LL*tmp2*19560929%p2;
//cout<<ans[j]<<' ';
}
//cout<<endl;
printf("%d %d\n",sum1,sum2);
}
}
return 0;
}
4.Lawn of the Dead
关键点在于只能向右或者向下走。假如一个障碍点,那么它右边的点想要到达,必须是从上面走过来的。那么对于两个障碍点中间这一段区间的点,能到达哪些点,取决于上一层的对应区间,能到达哪些点。问题转化成了区间整体赋值问题,我们可以把能到达的点赋值1,不能到达的赋值2.线段树即可。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+10;
const int inf=1e9;
vector<int>f[N];
int sum[N*4],d[N*4];
int t,n,m,k;
ll ans;
void pushdown(int p,int l,int r){
if(d[p]==-1) return;
int mid=l+r>>1;
sum[p*2]=(mid-l+1)*d[p];
sum[p*2+1]=(r-mid)*d[p];
d[p*2]=d[p*2+1]=d[p];
d[p]=-1;
}
void update(int p,int l,int r,int L,int R,int v){
if(L>R) return;
if(l>=L&&r<=R){
sum[p]=(r-l+1)*v;
d[p]=v;
return;
}//cout<<l<<' '<<r<<' '<<sum[p]<<' '<<L<<' '<<R<<' '<<v<<endl;
pushdown(p,l,r);
int mid=(l+r)/2;
if(L<=mid) update(p*2,l,mid,L,R,v);
if(R>mid) update(p*2+1,mid+1,r,L,R,v);
sum[p]=sum[p*2]+sum[p*2+1];
}
int query(int p,int l,int r,int L,int R){
//cout<<l<<' '<<r<<' '<<sum[p]<<' '<<L<<' '<<R<<endl;
if(l>=L&&r<=R){
if(sum[p]==r-l+1){
return l;
}
if(sum[p]==0) return inf;
}
if(r<L||l>R) return inf;
pushdown(p,l,r);
int mid=l+r>>1;
int temp=query(p*2,l,mid,L,R);
//cout<<l<<' '<<r<<' '<<sum[p]<<' '<<temp<<endl;
if(temp!=inf) return temp;
else return query(p*2+1,mid+1,r,L,R);
}
int main(){
scanf("%d",&t);
while(t--){
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++) f[i].push_back(0);
for(int i=1;i<=k;i++){
int x,y;scanf("%d%d",&x,&y);
f[x].push_back(y);
}
for(int i=1;i<=n;i++){
f[i].push_back(m+1);
sort(f[i].begin(),f[i].end());
}
ans=0;
ans+=f[1][1]-1;
update(1,1,m,1,f[1][1]-1,1);
for(int i=2;i<=n;i++){
for(int j=0;j<f[i].size()-1;j++){
int l=f[i][j]+1,r=f[i][j+1]-1;
//cout<<r+1<<endl;
if(r+1!=m+1)
update(1,1,m,r+1,r+1,0);
//cout<<sum[1]<<endl;cout<<endl;
if(l>r) {
continue;
}
// cout<<l<<' '<<r<<endl;
int temp=query(1,1,m,l,r);
//cout<<endl;
//cout<<sum(1)<<endl;
//cout<<l<<' '<<r<<' '<<temp<<endl;
if(temp!=inf){
ans+=r-temp+1;
update(1,1,m,l,min(r+1,m),0);
if(i!=n)
update(1,1,m,temp,r,1);
}
}
}
for(int i=1;i<=n;i++) f[i].clear();
cout<<ans<<endl;
}
return 0;
}
5.杭电9 1007 链表
题目描述:从1开始递增的往一个deque里插数,L就往左插,R就往又插,G x代表删去deque里的x,Q代表查询中位数。
分析:重点在于,每次插入一个新数或者删掉一个数,中位数只有三种情况:不动、向左移一个位置、向右移一个位置。而且到底什么情况很好判断,因此直接上链表。(太久没写链表,bug有点多,调了好久)
#include<bits/stdc++.h>
using namespace std;
const int N=1e7+10;
int q,cnt,tot,l,r,mid,now;
int po[N];
struct node{
int lef,rig,pos;
int v;
}e[N];
int main(){
//freopen("1.in","r",stdin);
//freopen("1.out","w",stdout);
scanf("%d",&q);
int n=1;
while(q--){
char ch=getchar();
while(ch=='\n') ch=getchar();
if(ch=='L'||ch=='R'){
if(tot==0){
cnt++;tot++;
e[cnt].pos=0;e[cnt].v=n;n++;
l=r=cnt;mid=l;po[n-1]=cnt;
}else{
if(ch=='L'){
e[l].lef=++cnt;tot++;
e[cnt].rig=l;e[cnt].pos=-1;
l=cnt;e[l].v=n;po[n]=cnt;n++;
if(tot%2){
int temp=mid;
mid=e[mid].lef;e[temp].pos=1;
e[mid].pos=0;
}
//cout<<e[e[2].lef].v<<' '<<e[e[2].rig].v<<endl;
}else{
e[r].rig=++cnt;tot++;
e[cnt].lef=r;r=cnt;e[cnt].pos=1;
e[cnt].v=n;po[n]=cnt;n++;
if(tot%2==0){
e[mid].pos=-1;
e[e[mid].rig].pos=0;
mid=e[mid].rig;
}
}
}
}else if(ch=='Q'){
printf("%d\n",e[mid].v);
}else if(ch=='G'){
int x;scanf("%d",&x);
now=po[x];
tot--;
if((tot+1)%2==0){
if(e[now].pos!=-1){
int temp=mid;
mid=e[mid].lef;
e[mid].pos=0;e[temp].pos=1;
}
}else{
if(e[now].pos!=1){
int temp=mid;
mid=e[mid].rig;
e[mid].pos=0;e[temp].pos=-1;
}
}
if(now==l){
int R=e[now].rig;e[R].lef=0;
l=R;
}else if(now==r){
int L=e[now].lef;e[L].rig=0;
r=L;
}else{
int L=e[now].lef,R=e[now].rig;
e[L].rig=R;e[R].lef=L;
}
//cout<<e[e[2].lef].v<<' '<<e[e[2].rig].v<<endl;
}
}
return 0;
}
6.杭电9 1002 Dota2
题目描述
假设现在我知道两个人最终跑了k轮,那么可以想到,如果k是偶数,对于后手来说,他最后一次移动一定是移动到当前列的最小值。但是先手想要值越大越好,因此最终到达的一定是列的最小值里最大的那一个。如果k是奇数且k大于1,那么再先手最后一次操作前,后手会干扰先手,那么取到的一定是行的最大值里的最小值。如果k=1,那么先手会直接取到第一行的最大值。
但是问题在于,这道题并不一定跑k轮。每个人是可以随时结束游戏的。但其实对我们答案有影响的只是进行轮数的奇偶性。如果k是奇数,那么先手一定不会结束游戏,因为如果先手结束游戏,相当于跑了偶数轮,这对他是不利的。后手自然也不会结束游戏,因为这个操作做了,轮数仍然是奇数,对它毫无意义。同理,如果k是偶数,先手结束游戏毫无意义,后手结束游戏对他不利。
总的来说就是先手后手虽然可以随时结束游戏,但其实他们最终还是跑满了k轮。
唯一需要注意的是,先手可以第一时间结束游戏,这样他就可以取到a11这个值。
7.C. Pty loves lines
题目描述
分析:
1、首先应想到怎么dp。考虑k条边可能产生的交点个数时,可以由i条边产生的交点数递推过来。设dp[i][j]表示i条边,产生j个交点是否成立,如果成立,那么dp[k][(k-i)*i+j]一定成立。因此可以写一个
n
4
n^{4}
n4的dp。这是hdu一道原题,n是20,可以通过.
2、但是现在这道题n是700,考虑如何优化。容易发现,用dp[i]推dp[k]时,只是把dp[i]的状态数组右移了(k-i)*i个位置。可以用bitset优化递推,复杂度变为
n
4
/
32
n^4/32
n4/32.
3、虽然bitset快了很多,但本地实测跑了7s左右,仍然不能通过本题。其实通过样例就可以发现,对于每个k来说,后面有很长一段答案是连续的。打表发现最大不能交出来的点不超过35000,复杂度变为
n
2
∗
35000
/
32
n^2*35000/32
n2∗35000/32.可以通过本题