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但我没码