noip模拟6

T1 辣鸡

大暴力,淦
考试的时候推出来了矩形内部氢键的式子,觉得数据肯定没有光是矩形内部的,就码了个sb模拟,结果RE+TLE.
正解很简单,就是个模拟我是sb.
分两部分来计算矩形对氢键个数的贡献,一部分为矩形内部,一部分为外部,内部直接套式子,外部分情况讨论一下就好,矩形上下相接,左右相接,对角相接,然后就没了。

Code
#include<cstdio>
#include<algorithm>
#define MAX 100001
#define re register
#define int long long
namespace OMA
{
   int n,ans;
   struct node
   {
     int x1,y1;
     int x2,y2;
   }p[MAX];
   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 int max(int a,int b)
   { return a>b?a:b; }
   bool cmp(node a,node b)
   { return a.x1<b.x1; }
   signed main()
   {
     n = read();
     for(re int i=1; i<=n; i++)
     { 
       p[i].x1 = read(),p[i].y1 = read(),p[i].x2 = read(),p[i].y2 = read();
       ans += (p[i].x2-p[i].x1)*(p[i].y2-p[i].y1); 
     }
     ans <<= 1;
     std::sort(p+1,p+1+n,cmp);
     for(re int i=1; i<=n; i++)
     {
       for(re int j=i+1;j<=n; j++)
       {
         if(p[j].x1>p[i].x2+1)
         { break; }
         int lenx = min(p[i].x2,p[j].x2)-max(p[i].x1,p[j].x1);
         int leny = min(p[i].y2,p[j].y2)-max(p[i].y1,p[j].y1);
         if(lenx>=0)
         {
           if(p[i].y2==p[j].y1-1||p[j].y2==p[i].y1-1)
           {
             ans += lenx<<1;
             if(p[i].x1!=p[j].x1)
             { ans++; }
             if(p[i].x2!=p[j].x2)
             { ans++; }
           }
         }
         if(leny>=0)
         {
           if(p[i].x2==p[j].x1-1)
           {
             ans += leny<<1;
             if(p[i].y1!=p[j].y1)
             { ans++; }
             if(p[i].y2!=p[j].y2)
             { ans++; }
           }
         }
         if(p[i].x2==p[j].x1-1&&(p[i].y1==p[j].y2+1||p[i].y2==p[j].y1-1))
         { ans++; }
       }
     }
     printf("%lld\n",ans);
     return 0;
   }
}
signed main()
{ return OMA::main(); }

T2 模板

30分直接搜,正解不会咕了
还是贴个30分的代码吧

30pts
#include<cstdio>
#define MAX 1001
#define re register
namespace OMA
{
   int n,m,q;
   int k[MAX];
   struct node
   {
     int next;
     int to;
   }edge[MAX<<1];
   int x,c;
   int dep[MAX];
   int ans[MAX];
   bool col[MAX][MAX];
   int cnt=1,head[MAX];
   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 void deep(int u,int fa)
   {
     for(re int i=head[u]; i; i=edge[i].next)
     {
       int v = edge[i].to;
       if(v!=fa)
       {
         dep[v] = dep[u]+1;
         deep(v,u);
       }
     }
   }
   inline void dfs(int u,int fa)
   {
     if(!col[u][c]&&k[u]>0)
     { ans[u]++; col[u][c] = true; /*printf("u=%d col=%d\n",u,c);*/ }
     k[u] -= (k[u]>0)?1:0;
     if(u==1)
     { return ; }
     for(re int i=head[u]; i; i=edge[i].next)
     {
       int v = edge[i].to;
       if(v!=fa&&dep[u]>dep[v])
       { dfs(v,u); }
     }
   }
   signed main()
   {
     n = read();
     for(re int i=1; i<=n-1; i++)
     {
       int u = read(),v = read();
       add(u,v),add(v,u);
     }
     deep(1,0);
     for(re int i=1; i<=n; i++)
     { k[i] = read(); }
     m = read();
     for(re int i=1; i<=m; i++)
     {
       x = read(),c = read();
       dfs(x,-1);
     }
     q = read();
     for(re int i=1; i<=q; i++)
     { printf("%d\n",ans[read()]); }
     return 0;
   }
}
signed main()
{ return OMA::main(); }

upd:学了线段树进阶,预计过一段时间就能改出来

T3 大佬

看到概率期望就跳了
好吧,考试快结束的时候看见有个点 \(k>n\) 输出0骗了5pts。
其实不难,首先给出式子

\[ans=\frac{\left(n-k+1\right)\times \sum_{i=1}^{m}wt_{i}\times \left({i}^{k}-\left(i-1\right)^{k}\right)}{m^{k}} \]

解释:
首先枚举的是难度i,\(i^{k}\) 表示的是选题的方案数,对于每一道题,其难度都有i种选择,即 \(i^{k}\) ,同时要容斥一下,排除掉难度最大的不是i的情况,即式子中的 \(\left(i-1\right)^{k}\),按照题意,要乘上题的难度才是劳累度,一共有 \(n-k+1\) 天,\(m^{k}\) 为总方案数。

总的说下来就是总的劳累度乘总的概率算出总的期望

Code
#include<cstdio>
#define MAX 501
#define re register
#define int long long
namespace OMA
{
   int n,m,k,ans,wt[MAX];
   const int p=1000000007;
   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 quickpow(int a,int b)
   {
     int ans = 1;
     while(b)
     {
       if(b&1)
       { ans = ans*a%p; }
       a = a*a%p;
       b >>= 1;
     }
     return ans;
   }
   signed main()
   {
     n = read(),m = read(),k = read();
     for(re int i=1; i<=m; i++)
     { wt[i] = read(); }
     if(k>n)
     { printf("0\n"); return 0; }
     for(re int i=1; i<=m; i++)
     { ans = (ans+((quickpow(i,k)-quickpow(i-1,k))*wt[i]))%p; }
     ans = ans*(n-k+1)%p;
     int inv = quickpow(quickpow(m,k),p-2)%p;
     printf("%lld\n",(ans*inv%p+p)%p);
     return 0;
   }
}
signed main()
{ return OMA::main(); }

T4

宝藏
小蓝书上有。
其实也可以打暴搜,就是剪枝有些麻烦。
还有模拟退火,但TLEer现在最多拿了95pts
20pts拿的是树的分,直接搜就可
以下代码为爆搜+剪枝 70ms碾压标算

Code
#include<cstdio>
#include<algorithm>
#define re register
#define MAX 114514810
namespace OMA
{
   int n,m;
   int ans=MAX;
   int edge[21][21],du[21];
   int dep[21],dis[21][21];
   int vis[21],cnt;
   int u,v,w,sum,temp;
   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 bool cmp(int a,int b)
   { return dis[u][a]<dis[u][b]; }
   inline int min(int a,int b)
   { return a<b?a:b; }
   void dfs(int now,int ord)
   {
     for(re int i=now; i<=cnt; i++)
     {
       if(sum+temp*dep[vis[i]]>=ans)
       { return ; }
       for(re int j=ord; j<=du[vis[i]]; j++)
       {
         if(!dep[edge[vis[i]][j]])
         {
           vis[++cnt] = edge[vis[i]][j];
           temp -= dis[vis[cnt]][edge[vis[cnt]][1]];
           sum += dep[vis[i]]*dis[vis[i]][vis[cnt]];
           dep[vis[cnt]] = dep[vis[i]]+1;
           dfs(i,j+1);
           temp += dis[vis[cnt]][edge[vis[cnt]][1]];
           sum -= dep[vis[i]]*dis[vis[i]][vis[cnt]];
           dep[vis[cnt--]] = 0;
         }
       }
       ord = 1;
     }
     ans = (cnt==n)?min(ans,sum):ans;
   }
   signed main()
   {
     n = read(),m=read();
     for(re int i=1; i<=n; i++)
     {
       for(re int j=1; j<=n; j++)
       { dis[i][j] = MAX; }
     }
     for(re int i=1; i<=m; i++)
     {
       u=read(),v=read(),w=read();
       if(dis[u][v]<w)
       { continue; }
       if(dis[u][v]==MAX)
       { edge[u][++du[u]] = v,edge[v][++du[v]] = u; }
       dis[u][v] = dis[v][u] = w;
     }
     for(re int i=1; i<=n; i++)
     {
       std::sort(edge[u=i]+1,edge[i]+1+du[i],cmp);
       temp += dis[i][edge[i][1]];
     }
     for(re int i=1; i<=n; i++)
     {
       sum = 0;
       cnt = dep[i] = 1;
       temp -= dis[i][edge[vis[1]=i][1]];
       dfs(1,1);
       dep[i] = 0;
       temp += dis[i][edge[i][1]];
     }
     printf("%d\n",ans);
     return 0;
   }
}
signed main()
{ return OMA::main(); }

正解是状压dp但我没码

posted @ 2021-06-10 17:47  -OMA-  阅读(84)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end