noip模拟测试19


T1:Count

  首先容易发现块的大小一定是n的约数,枚举约数$O(\sqrt n)$

  考虑怎么判定

  设块大小为k

  发现只要最下方的子树$(a)$大小是$k$,包含a的子树$(b)$大小是$2k$,包含b的子树$(c)$大小是$3k$……

  即:只需要有$n/k$个子树的大小是$k$的倍数即可

  所以就可以$O(n)$的判定了,然后就无脑提交$O(n \sqrt n )$过百万???

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cstdlib>
#include<vector>
using namespace std;
const int MAXN=1000005;
int n,ans,siz[MAXN];
struct node {
    int to,nxt;
}mp[MAXN*2];
int h[MAXN],tot;
void dfs(int u,int fa) {
    siz[u]=1;
    for(int i=h[u];i;i=mp[i].nxt) {
        int v=mp[i].to;
        if(v==fa) continue;
        dfs(v,u);
        siz[u]+=siz[v];
    }
}
inline int R() {
    int a=0;char c=getchar();
    while(c>'9'||c<'0')c=getchar();
    while(c>='0'&&c<='9')a=a*10+c-'0',c=getchar();
    return a;
}
int main() {
    n=R();
    for(int i=1,aa,bb;i<n;++i) {
        aa=R();bb=R();
        mp[++tot].nxt=h[aa];
        mp[tot].to=bb;h[aa]=tot;
        mp[++tot].nxt=h[bb];
        mp[tot].to=aa;h[bb]=tot;
    }
    dfs(1,0);
    for(int i=2;i<n;++i) if(n%i==0) {
        int cnt=0;
        for(int j=1;j<=n;j++)
            if(siz[j]%i==0) ++cnt;
        if(n/i==cnt) ++ans;
    }
    printf("%d\n",ans+2);
    return 0;
}
t1 Code

 


T2:Dinner

  没想到倍增,想到了二分可以跳到的点,但m的范围没有给,若m与n同级复杂度就爆了,所以没写

  结果发现m实际上很小,好多人都用二分水过了……

  

  首先断环成链,二分答案

  最暴力的判定是枚举端点,再一步一步贪心的跳,复杂度$O(n^2logn)$

  考虑优化跳的复杂度

  对于每次check,可以$O(nlogn)$的预处理跳$2^n$步可以跳到哪里

  然后把m二进制拆开跳,复杂度$O((nlogn+logm)*logn)$,若m与n同级$O(nlog^2n)$

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<iostream>
 6 #include<queue>
 7 #include<cstdlib>
 8 #include<vector>
 9 using namespace std;
10 const int MAXN=50005;
11 int n,m,ans,suma,mx,t[MAXN*2],nxt[MAXN*2][20];
12 inline int R() {
13     int a=0;char c=getchar();
14     while(c>'9'||c<'0')c=getchar();
15     while(c>='0'&&c<='9')a=a*10+c-'0',c=getchar();
16     return a;
17 }
18 bool check(int lim) {
19     for(int i=1;i<=n;i++) {
20         int pos=i,tm=m;
21         for(int j=18;j>=0;j--) {
22             if((1<<j)>tm) continue;
23             pos=nxt[pos][j];
24             tm-=(1<<j);
25         }
26         if(pos-i>=n) return 1;
27     }
28     return 0;
29 }
30 void first(int lim) {
31     int l=1,sum=0;
32     for(int i=1;i<=2*n;i++)
33         if(sum+t[i]<=lim) sum+=t[i];
34         else {
35             while(l<i&&sum+t[i]>lim) {
36                 nxt[l][0]=i;
37                 sum-=t[l];
38                 ++l;
39             }
40             sum+=t[i];
41         }
42     while(l<=2*n) nxt[l][0]=2*n+1,++l;
43     for(int i=0;i<=18;i++) nxt[2*n+1][i]=2*n+1;
44     for(int i=1;i<=18;i++)
45         for(int j=1;j+(1<<(i-1))<=2*n;j++)
46             nxt[j][i]=nxt[nxt[j][i-1]][i-1];
47 }
48 int main() {
49     scanf("%d%d",&n,&m);
50     for(int i=1;i<=n;++i) scanf("%d",&t[i]);
51     for(int i=1;i<=n;++i)
52         t[i+n]=t[i],suma+=t[i],mx=max(mx,t[i]);
53     int l=mx,r=suma;
54     while(l<=r) {
55         int mid=(l+r)>>1;
56         first(mid);
57         if(check(mid))
58             ans=mid,r=mid-1;
59         else l=mid+1;
60     }
61     printf("%d\n",ans);
62     return 0;
63 }
t2 Code

 


 

T3:Chess

  首先第一问很简单,可以直接双端队列bfs或建图跑最短路

  然后看第二问,发现只有走的空地不同才算不同的方案

  发现n的范围很小,于是对于dfs每一个敌军的连通块,看它连接着哪些空地,在这些空地间两两连边

  再将直接可以到达的两空地间连边

  特别的:可以将敌人的帅看做一个空地进行连边

  跑最短路计数就行了

  注意:相同的边只能连一次,所以可以用邻接矩阵来存边

  (有点毒瘤……)

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #include<cstdlib>
  5 #include<cmath>
  6 #include<iostream>
  7 #include<queue>
  8 #include<vector>
  9 #define ll long long
 10 using namespace std;
 11 const int MAXN=70,INF=0x3f3f3f3f;
 12 int n,m,bx,by,ex,ey,eid,s[MAXN][MAXN];
 13 int dx[8]={-1,-2,-2,-1,1,2,2,1},dy[8]={-2,-1,1,2,2,1,-1,-2};
 14 struct node {
 15     int to,nxt,dis;
 16 }mp[MAXN*MAXN*8];
 17 int h[MAXN*MAXN],tot;
 18 int id(int x,int y) {
 19     return (x-1)*m+y;
 20 }
 21 void add(int x,int y,int z) {
 22     mp[++tot].dis=z;
 23     mp[tot].to=y;
 24     mp[tot].nxt=h[x];
 25     h[x]=tot;
 26 }
 27 void build() {
 28     for(int i=1;i<=n;i++) {
 29         for(int j=1;j<=m;j++) {
 30             if(s[i][j]==2) continue;
 31             if(s[i][j]==4) {ex=i,ey=j;continue;}
 32             if(s[i][j]==3) bx=i,by=j;
 33             for(int k=0;k<8;k++) {
 34                 int nx=i+dx[k],ny=j+dy[k];
 35                 if(nx<1||ny<1||nx>n||ny>m) continue;
 36                 if(s[nx][ny]==2) continue;
 37                 add(id(i,j),id(nx,ny),s[nx][ny]!=1&&s[nx][ny]!=4);
 38             }
 39         }
 40     }
 41 }
 42 int ver[MAXN*MAXN][MAXN*MAXN],dis[MAXN*MAXN];
 43 vector<int> tver;
 44 bool vis[MAXN*MAXN],flag;
 45 void dfs(int u) {
 46     for(int i=h[u];i;i=mp[i].nxt) {
 47         int v=mp[i].to;
 48         if(vis[v]) continue;
 49         vis[v]=1;
 50         if(v==eid) flag=1;
 51         if(!mp[i].dis) dfs(v);
 52         else if(mp[i].dis==1) tver.push_back(v);
 53     }
 54 }
 55 void new_build() {
 56     eid=id(ex,ey);
 57     memset(vis,0,sizeof(vis));
 58     for(int i=1;i<=n;i++) {
 59         for(int j=1;j<=m;j++) if(s[i][j]==1){
 60             tver.clear();flag=0;
 61             vis[id(i,j)]=1;dfs(id(i,j));
 62             for(int k=0;k<tver.size();++k)
 63                 for(int l=0;l<tver.size();++l)
 64                     ver[tver[k]][tver[l]]=ver[tver[l]][tver[k]]=1;
 65             if(flag) for(int k=0;k<tver.size();++k)
 66                         ver[tver[k]][eid]=1;
 67             memset(vis,0,sizeof(vis));
 68         }
 69     }
 70     for(int i=1;i<=n;i++)
 71         for(int j=1;j<=m;j++) if(s[i][j]==0||s[i][j]==3)
 72             for(int k=h[id(i,j)];k;k=mp[k].nxt)
 73                 if(mp[k].dis||mp[k].to==eid)
 74                     ver[id(i,j)][mp[k].to]=ver[mp[k].to][id(i,j)]=1;
 75 }
 76 ll cnt[MAXN*MAXN];
 77 void get_cnt() {
 78     memset(dis,0x3f,sizeof(dis));
 79     dis[id(bx,by)]=0;cnt[id(bx,by)]=1;
 80     priority_queue<pair<int,int> > q;
 81     q.push(make_pair(0,id(bx,by)));
 82     while(!q.empty()) {
 83         int u=q.top().second; q.pop();
 84         if(vis[u]) continue;
 85         vis[u]=1;
 86         for(int i=1;i<=n*m;i++) if(i!=u){
 87             int v=i,ds=ver[u][i];
 88             if(!ds) continue;
 89             if(dis[v]>dis[u]+ds) {
 90                 dis[v]=dis[u]+ds;
 91                 cnt[v]=cnt[u];
 92                 q.push(make_pair(-dis[v],v));
 93             } else if(dis[v]==dis[u]+ds) cnt[v]+=cnt[u];
 94         }
 95     }
 96     printf("%lld\n",cnt[eid]);
 97 }
 98 void dijkstra() {
 99     priority_queue<pair<int,int> > q;
100     q.push(make_pair(0,id(bx,by)));
101     memset(dis,0x3f,sizeof(dis));
102     dis[id(bx,by)]=0;
103     while(!q.empty()) {
104         int u=q.top().second; q.pop();
105         if(vis[u]) continue;
106         vis[u]=1;
107         for(int i=h[u];i;i=mp[i].nxt) {
108             int v=mp[i].to,ds=mp[i].dis;
109             if(dis[v]>dis[u]+ds) {
110                 dis[v]=dis[u]+ds;
111                 q.push(make_pair(-dis[v],v));
112             }
113         }
114     }
115     if(dis[id(ex,ey)]==INF) {
116         printf("-1\n");exit(0);
117     } else printf("%d\n",dis[id(ex,ey)]);
118 }
119 int main() {
120     scanf("%d%d",&n,&m);
121     for(int i=1;i<=n;i++)
122         for(int j=1;j<=m;j++)
123             scanf("%d",&s[i][j]);
124     build();
125     dijkstra();
126     new_build();
127     get_cnt();
128     return 0;
129 }
t3 Code

 

posted @ 2019-08-14 20:04  G_keng  阅读(206)  评论(0编辑  收藏  举报