A - Mike and Cellphone
问有没有多解,每个点按照给出的序列用向量法跑一遍
#include<cstdio> #include<cstring> #include<queue> #include<cstdlib> #include<algorithm> #include<vector> #include<cmath> #include<map> using namespace std; typedef long long LL; const int N=2e5+5; const int INF=0x3f3f3f3f; char s[15]; int a[15],n; int mp[5][4]={-1,-1,-1,-1, -1,1,2,3, -1,4,5,6, -1,7,8,9, -1,-1,0,-1 }; typedef pair<int,int> pii; pii pos[10]; bool judge(int num){ int x=pos[num].first,y=pos[num].second; for(int i=2;i<=n;++i){ int px=pos[a[i]].first-pos[a[i-1]].first; int py=pos[a[i]].second-pos[a[i-1]].second; x+=px;y+=py; if(x<1||x>4||y<1||y>3)return false; if(mp[x][y]==-1)return false; } return true; } int main(){ scanf("%d%s",&n,s+1); if(n==1){printf("NO ");return 0;} for(int i=1;i<=n;++i) a[i]=s[i]-'0'; for(int i=1;i<=4;++i){ for(int j=1;j<=3;++j){ if(mp[i][j]==-1)continue; pos[mp[i][j]].first=i; pos[mp[i][j]].second=j; } } bool flag=false; for(int i=0;i<=9;++i) if(i!=a[1]&&judge(i)){flag=true;break;} if(flag)printf("NO "); else printf("YES "); return 0; }
B - Mike and Shortcuts
可能有更优的办法,一看数据,dij最短路水过
#include<cstdio> #include<cstring> #include<queue> #include<cstdlib> #include<algorithm> #include<vector> #include<cmath> #include<map> using namespace std; typedef long long LL; const int N=2e5+5; const int INF=0x3f3f3f3f; struct Edge{ int v,next; LL w; Edge(int a=0,LL b=0){v=a,w=b;} bool operator<(const Edge &e)const{ return w>e.w; } }edge[N*3]; int head[N],tot,n; LL d[N]; void add(int u,int v,int w){ edge[tot].v=v; edge[tot].w=w; edge[tot].next=head[u]; head[u]=tot++; } priority_queue<Edge>q; bool vis[N]; void dij(int s){ for(int i=1;i<=n;++i)d[i]=INF,vis[i]=0; d[s]=0,q.push(Edge(s,0)); while(!q.empty()){ int u=q.top().v; q.pop(); if(vis[u])continue; vis[u]=1; for(int i=head[u];~i;i=edge[i].next){ int v=edge[i].v; if(!vis[v]&&d[v]>d[u]+edge[i].w){ d[v]=d[u]+edge[i].w; q.push(Edge(v,d[v])); } } } } int main(){ scanf("%d",&n); memset(head,-1,sizeof(head)); for(int i=1;i<=n;++i){ int x;scanf("%d",&x); add(i,x,1); } for(int i=1;i<n;++i){ add(i,i+1,1); add(i+1,i,1); } dij(1); for(int i=1;i<n;++i)printf("%I64d ",d[i]); printf("%I64d ",d[n]); return 0; }
C - Mike and Chocolate Thieves
直接二分找就行,注意二分的移动
#include<cstdio> #include<cstring> #include<queue> #include<cstdlib> #include<algorithm> #include<vector> #include<cmath> #include<map> using namespace std; typedef long long LL; const int N=2e5+5; const int INF=0x3f3f3f3f; LL judge(LL mid){ LL sum=0; for(LL i=2;i<=1000000;++i){ sum+=mid/(i*i*i); } return sum; } int main(){ LL m; scanf("%I64d",&m); LL l=1,r=1ll*1e18,ret=-1; while(l<=r){ LL mid=(l+r)>>1; LL tmp=judge(mid); if(tmp>m)r=mid-1; else if(tmp==m)ret=mid,r=mid-1; else l=mid+1; } printf("%I64d ",ret); return 0; }
D - Friends and Subsequences
这个题,不知道是我线段树写残了,还是线段树常数大,死活超时,RMQ才过,哪天去学一发ZKW线段树的姿势吧
#include <vector> #include <iostream> #include <queue> #include <cmath> #include <map> #include <cstring> #include <algorithm> #include <cstdio> using namespace std; #define For(i,j,n) for(int i=j;i<=n;i++) #define Riep(n) for(int i=1;i<=n;i++) #define Riop(n) for(int i=0;i<n;i++) #define Rjep(n) for(int j=1;j<=n;j++) #define Rjop(n) for(int j=0;j<n;j++) #define mst(ss,b) memset(ss,b,sizeof(ss)); typedef long long LL; template<class T> void read(T&num) { char CH; bool F=false; for(CH=getchar();CH<'0'||CH>'9';F= CH=='-',CH=getchar()); for(num=0;CH>='0'&&CH<='9';num=num*10+CH-'0',CH=getchar()); F && (num=-num); } int stk[70], tp; template<class T> inline void print(T p) { if(!p) { puts("0"); return; } while(p) stk[++ tp] = p%10, p/=10; while(tp) putchar(stk[tp--] + '0'); putchar(' '); } const LL mod=1e9+7; const double PI=acos(-1.0); const LL inf=1e18; const int N=2e5+10; const int maxn=1005; const double eps=1e-10; int a[N],b[N],MX[N][21],MN[N][21],n; struct Tree { int l,r; int mmax,mmin; }tr[4*N]; void build(int o,int L,int R) { for(int i=1;i<=n;i++) MX[i][0]=a[i],MN[i][0]=b[i]; for(int j=1;(1<<j)<=n;j++) { for(int i=1;i+(1<<j)-1<=n;i++) { MX[i][j]=max(MX[i][j-1],MX[i+(1<<(j-1))][j-1]); MN[i][j]=min(MN[i][j-1],MN[i+(1<<(j-1))][j-1]); } } } int query(int o,int L,int R,int flag) { if(flag) { int k = 0; while( (1<<(k+1)) <= R-L+1) k ++ ; return max(MX[L][k],MX[R-(1<<k)+1][k]); } else { int k = 0; while( (1<<(k+1)) <= R-L+1) k ++ ; return min(MN[L][k],MN[R-(1<<k)+1][k]); } } int judge(int x,int y) { int mx=query(1,x,y,1),mn=query(1,x,y,0); if(mx==mn)return 1; else if(mx>mn)return 2; return 0; } int main() { read(n); For(i,1,n)read(a[i]); For(i,1,n)read(b[i]); build(1,1,n); LL ret=0; for(int i=1;i<=n;++i){ int ans1=-1,ans2=-1; int l=i,r=n; while(l<=r){ int m=l+r>>1; int t=judge(i,m); if(t==1)ans1=m,r=m-1; else if(t==2)r=m-1; else l=m+1; } l=i,r=n; while(l<=r){ int m=l+r>>1; int t=judge(i,m); if(t==1)ans2=m,l=m+1; else if(t==2)r=m-1; else l=m+1; } if(ans1!=-1&&ans2!=-1)ret+=ans2-ans1+1; } printf("%I64d ",ret); return 0; }
E - Mike and Geometry Problem
区间题,转化一下,看每个点被多少个线段覆盖(离散化搞搞),相同覆盖数统计,然后用组合数就行
#include <vector> #include <iostream> #include <queue> #include <cmath> #include <map> #include <cstring> #include <algorithm> #include <cstdio> using namespace std; typedef long long LL; const int N=2e5+5; const LL mod=1e9+7; struct Segment{ int l,r; }p[N]; int pos[N*2],n,k,tot,a[N*2],b[2*N]; LL dp[N],fac[N],inv[N]; LL quick_pow(LL a,LL num){ LL ret=1; while(num){ if(num&1)ret=(ret*a)%mod; num>>=1; a=(a*a)%mod; } return ret; } LL C(LL n,LL m){ return (fac[n]*inv[n-m])%mod*inv[m]%mod; } int main() { scanf("%d%d",&n,&k); inv[0]=fac[0]=1; for(int i=1;i<=n;++i){ fac[i]=1ll*i*fac[i-1]%mod; inv[i]=quick_pow(fac[i],mod-2); } for(int i=1;i<=n;++i){ scanf("%d%d",&p[i].l,&p[i].r); pos[++tot]=p[i].l; pos[++tot]=p[i].r; } sort(pos+1,pos+1+tot); tot=unique(pos+1,pos+1+tot)-pos-1; for(int i=1;i<=n;++i){ p[i].l=lower_bound(pos+1,pos+1+tot,p[i].l)-pos; p[i].r=lower_bound(pos+1,pos+1+tot,p[i].r)-pos; ++a[p[i].l],--b[p[i].r]; } for(int i=1;i<=tot;++i){ a[i]+=a[i-1]; ++dp[a[i]]; if(i!=1)dp[a[i-1]]+=max(0,pos[i]-pos[i-1]-1); a[i]+=b[i]; } LL ret=0; for(int i=k;i<=n;++i){ ret=(ret+dp[i]*C(i,k)%mod)%mod; } printf("%I64d ",ret); return 0; }