noip10

T1

直接暴力可拿60pts,不开 long long 会挂5pts,时间复杂度
\(\mathcal O(n^{4})\) , 然而这过不了400的数据,至少也要 \(\mathcal O(n^{3})\),然后,考试的时候就想不出来了。

正解,枚举行,计算出模 \(k\) 意义下余数相同的矩阵的个数,统计答案即可。

Code
#include<cstdio>
#define MAX 1000001
#define re register
#define int long long
namespace OMA
{
   int n,m,p,ans;
   int sum[401][401];
   int cnt[MAX],pre[401];
   inline int read()
   {
     int s=0,w=1; char ch=getchar();
     while(ch<'0'||ch>'9'){ if(ch=='-')w=-1; ch=getchar(); }
     while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); }
     return s*w;
   }
   signed main()
   {
     n = read(),m = read(),p = read();
     for(re int i=1; i<=n; i++)
     {
       for(re int j=1; j<=m; j++)
       { (sum[i][j] += sum[i-1][j]+sum[i][j-1]+read()-sum[i-1][j-1]+p) %= p; }
     }
     for(re int i=0; i<=n-1; i++)
     {
       for(re int j=i+1; j<=n; j++)
       {       
         cnt[0] = 1;
         for(re int k=1; k<=m; k++)
         { ans += cnt[(pre[k] = sum[j][k]-sum[i][k]+p) %= p]++; }
         for(re int k=1; k<=m; k++)
         { cnt[pre[k]] = 0; }
       }
     }
     printf("%lld\n",ans);
     return 0;
   }
}
signed main()
{ return OMA::main(); }

T2

\(k=0\) 时,直接输出 \(n\) ,5pts。
\(k=1\) 时。直接树形dp,类似于小胖守皇宫,40pts。

正解:

  • 可以用树形dp过,但不好搞,不过大帝做到了。
  • 贪心,我们设 \(dp_{u,0}\) 表示 \(u\) 到最近被控制点的距离, \(dp_{u,1}\) 表示 \(u\) 到最远没被控制点的距离。
    初始化,\(dp_{u,0}=\infty,dp_{u,1}=0\)
    \(dp_{u,0}+dp_{u,1}<=k\) 时,说明该节点能被控制,不会对答案有贡献。 \(dp_{u,1}=-1\)
    \(dp_{u,1}=k\) 时,此时该点必须被控制,这时已经达到能控制点的的最远距离,如果再向上的话,则无法控制 \(u\)\(dp_{u,0}=0,dp_{u,1}=-1\)
    记得特判一下根节点能否被控制。
  • 还有种 \(\mathcal O(n)\) 做法
Code
#include<cstdio>
#define MAX 100001
#define re register
namespace OMA
{
   int n,k,t;
   struct Graph
   {
     int next;
     int to;
   }edge[MAX<<1];
   int cnt=1,head[MAX];
   int dp[MAX][2],ans;
   inline int read()
   {
     int s=0,w=1; char ch=getchar();
     while(ch<'0'||ch>'9'){ if(ch=='-')w=-1; ch=getchar(); }
     while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); }
     return s*w;
   }
   inline void add(int u,int v)
   {
     edge[++cnt].next = head[u];
     edge[cnt].to = v;
     head[u] = cnt;
   }
   inline int min(int a,int b)
   { return a<b?a:b; }
   inline int max(int a,int b)
   { return a>b?a:b; }
   inline void dfs(int u,int fa)
   {
     dp[u][0] = 0x3f,dp[u][1] = 0;
     for(re int i=head[u]; i; i=edge[i].next)
     {
       int v = edge[i].to;
       if(v!=fa)
       {
         dfs(v,u);
         if(~dp[v][1])
         { dp[u][1] = max(dp[u][1],dp[v][1]+1); }
         dp[u][0] = min(dp[u][0],dp[v][0]+1);
       }
     }
     if(dp[u][1]==k)
     { ans++,dp[u][0] = 0,dp[u][1] = -1; }
     if(dp[u][0]+dp[u][1]<=k)
     { dp[u][1] = -1; }
   }
   signed main()
   {
     n = read(),k = read(),t = read();
     for(re int i=1; i<=n-1; i++)
     {
       int u = read(),v = read();
       add(u,v),add(v,u);
     }
     dfs(1,0);
     if(~dp[1][1])
     { ans++; }
     printf("%d\n",ans);
     return 0;
   }
}
signed main()
{ return OMA::main(); }

T3

考试的时候想了状压 \(k\) ,但是不会看到范围才想的状压
直接输出1,4pts。
对于 \(n\le16\) ,直接状压,24pts。
对于 \(m=1\) ,的情况,直接从前往后扫,遇见没亮的就点,28pts。
玄学 \(rand()\) ,可骗0~12pts不等 TLEer拿阳寿换的12pts

正解:

神仙转换。
先咕了QAQ

Code
#include<queue>
#include<cstdio>
#define MAX 40001
#define re register
namespace OMA
{
   int n,k,m,cnt;
   std::queue<int>q;
   int vis[MAX],dis1[MAX];   
   int a[MAX],b[70],p[MAX];
   int dis[20][20],top,dp[1<<17];
   inline int read()
   {
     int s=0,w=1; char ch=getchar();
     while(ch<'0'||ch>'9'){ if(ch=='-')w=-1; ch=getchar(); }
     while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); }
     return s*w;
   }
   inline int min(int a,int b)
   { return a<b?a:b; }
   inline void bfs(int u)
   {
     for(re int i=0; i<=n; i++)
     { dis1[i] = vis[i] = 0; }
     q.push(u);
     vis[u] = true;
     while(!q.empty())
     {
       int k = q.front(); q.pop();
       for(re int i=1; i<=m; i++)
       {
         int v[2] = {k-b[i],k+b[i]};
         if(v[0]>=0&&!vis[v[0]])
         { q.push(v[0]),dis1[v[0]] = dis1[k]+(vis[v[0]] = 1); }
         if(v[1]<=n&&!vis[v[1]])
         { q.push(v[1]),dis1[v[1]] = dis1[k]+(vis[v[1]] = 1); }
       }
     }
   }
   signed main()
   {
     n = read(),k = read(),m = read();
     for(re int i=1; i<=k; i++)
     { a[read()] = 1; }
     for(re int i=1; i<=m; i++)
     { b[i] = read(); }
     for(re int i=0; i<=n; i++)
     {
       if(a[i]^a[i+1])
       { p[++cnt] = i; }
     }
     for(re int i=1; i<=cnt; i++)
     {
       bfs(p[i]);
       for(re int j=1; j<=cnt; j++)
       { dis[i][j] = dis1[p[j]]; }
     }
     top = (1<<cnt)-1;
     for(re int i=1; i<=top; i++)
     { dp[i] = 0x3f3f3f3f; }
     for(re int i=0; i<=top; i++)
     {
       int k = 0;
       while(i&(1<<k))
       { k++; }
       for(re int j=k+1; j<=cnt-1; j++)
       {
         if(!(i&(1<<j))&&dis[j+1][k+1])
         { dp[i|(1<<j)|(1<<k)] = min(dp[i|(1<<j)|(1<<k)],dp[i]+dis[j+1][k+1]); }
       }
     }
     printf("%d\n",dp[top]);
     return 0;
   }
}
signed main()
{ return OMA::main(); }
posted @ 2021-06-27 00:00  -OMA-  阅读(82)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end