昨晚打开的题想了一会发现都不会后决定慢慢想。然后早上开校会的时候莫名其妙的都想出来了。。。

T1:m=100,ai=50000,i<=5。1到m的数每个数只能用一次,判断是否能够有这些数的某些数相乘得到ai

=>啊O(mai)的dp?利用质因数分解来写?不会。不会。直到早上觉得数据范围那么小写个爆搜+剪枝应该能过吧,毕竟是T1。而且50000的话每个数的因数都挺少的。

正解:

预处理出剩下前k张卡片时对于每个质因数最多可以贡献多少次幂。若搜索到一个状态,就算剩下的卡片所有都可以使用且不考虑分配原则的情况下仍无法约去所有质因数,则必定无解,可以进行剪枝操作。再配合算法一,期望得分100%。

#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
using namespace std;
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define clr(x,c) memset(x,c,sizeof(x))
int read(){
int x=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) x=x*10+c-'0',c=getchar();
return x;
}
const int nmax=1e3+5;
const int inf=0x7f7f7f7f;
int a[10][nmax],t[10],n,m;
bool vis[nmax];
bool dfs(int x,int pre,int now){
if(x>n) return 1;
int td=t[x]/now;
if(td<=a[x][pre]) return 0;
if(td<=m&&!vis[td]) {
vis[td]=1;
if(dfs(x+1,0,1)) return 1;
vis[td]=0;
}
rep(i,pre+1,a[x][0]){
if(td%a[x][i]==0&&!vis[a[x][i]]) {
vis[a[x][i]]=1;
if(dfs(x,i,now*a[x][i])) return 1;
vis[a[x][i]]=0;
}
}
return 0;
}
int main(){
freopen("cards.in","r",stdin);freopen("cards.out","w",stdout);
int T=read();
rep(_T,1,T){
clr(vis,0);
n=read(),m=read();
rep(i,1,n) t[i]=read();
rep(i,1,n) a[i][0]=0;
rep(i,1,n) rep(j,2,m) if(t[i]%j==0) a[i][++a[i][0]]=j;
if(!dfs(1,0,1)) puts("Yes");else puts("No");
}
fclose(stdin);fclose(stdout);
return 0;
}
/*
4
2 3
2 3
2 3
3 6
2 5
4 6
2 7
24 30
*/

T2:给出一个n*m的矩阵。矩阵中的数表示高度。给出初始水的高度和出水口。求出每个点最后的高度。

=>嗯矩阵这铁定应该是乱搞+bfs。。然后我就想着乱搞啊乱搞啊。。死定了。。然后在一个地方卡住了,有可能有很多条路径可以走啊这bfs的顺序根本没办法保证啊这。。。然后突然发现这不是最短路吗?我的思维能力还是太弱了。。。但是终于想出来了happy。spfa新写法被坑了好久。。

=>裸的spfa只能70分。正解要加个SLF优化。。。不会写。。。

正解:

对于某个点,设T表示流完水后,此点的高度(如果上面没水,就是它本身的高度,否则就是水的高度)。同时,T又可以表示此点到源点的路径上,经过的最小的T的值,毫无疑问,我们就是需要让每个点的T最小。并且,如果某点的T表示的是水的高度,他就可以被他周围的,比他小的T更新。

最后每个点的答案就是他的T减他本身的高度。期望得分70%。

SPFA加入经典的SLF优化,就可以通过100%的数据了。

#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#include<queue>
using namespace std;
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define clr(x,c) memset(x,c,sizeof(x))
int read(){
int x=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) x=x*10+c-'0',c=getchar();
return x;
}
const int nmax=805;
const int inf=0x7f7f7f7f;
int dist[nmax][nmax],a[nmax][nmax],mp[nmax][nmax];
int xx[4]={0,0,1,-1};
int yy[4]={1,-1,0,0};
int q[16777216][2];bool inq[nmax][nmax];
int main(){
freopen("shower.in","r",stdin);freopen("shower.out","w",stdout);
int n=read(),m=read(),h=read();
rep(i,1,n) rep(j,1,m) a[i][j]=read();
int sa=read(),sb=read();
rep(i,1,n) rep(j,1,m) mp[i][j]=max(a[i][j]-a[sa][sb],0);
if(h<a[sa][sb]) {
rep(i,1,n){
rep(j,1,m) printf("%d ",max(h-a[i][j],0));printf("\n");
}
return 0;
}
clr(dist,0x7f);dist[sa][sb]=0;
int ql=0,qr=1,x,y,tx,ty,td;q[qr][0]=sa;q[qr][1]=sb;
while(ql!=qr){ //这里不能是ql<qr!!!!!!!
ql=((ql+1)&1048575);x=q[ql][0];y=q[ql][1];inq[x][y]=0;
rep(i,0,3){
tx=x+xx[i];ty=y+yy[i];
if(tx<1||ty<1||tx>n||ty>m) continue;
td=max(dist[x][y],mp[tx][ty]);
if(dist[tx][ty]>td){
dist[tx][ty]=td;
if(!inq[tx][ty]){
inq[tx][ty]=1;qr=((qr+1)&1048575);
q[qr][0]=tx;q[qr][1]=ty;
}
}
}
}
rep(i,1,n){
rep(j,1,m) printf("%d ",dist[i][j]+a[sa][sb]-a[i][j]);printf("\n");
}
fclose(stdin);fclose(stdout);
return 0;
}
/*
3 3 66
6 9 1
7 8 1
6 8 1
3 2
*/

T3:给出两颗树,在两棵树的任两个点连边可以形成一棵树。求n*m种树的最长路径。

=>很明显应该先求出原树中每个点的最长路径。这个树形dp一下可以解决。然后接下来就是有可能是原树中的路径或是经过新加入的边的路径。那么sort一下然后二分找出那么临界点就可以了。复杂度O(nlogn)。ps:其实nm1e5根本不用sort好不TAT。。。。

正解:

明显地,如果我们确定了i点(不妨设i在N个点的树上),要在另一棵树上找到j点使得新生成的最长链是直径,则只需要满足f(j)>len-1-f(i),如此可以使用桶维护s(x)表示有多少f(j)是小于等于x的,那么确定了i后,f(i)会对答案贡献M-s(len-1-f(i))次,本身两棵树上的较长直径会对答案贡献s(len-1-f(i))次。

对于快速地求出所有的f(i)我们可以选择树形DP后旋根。

在树形DP内我们可以记f(i)为i到以i节点为根的子树下任意节点的最长链。G(i)为与f(i)不相交的次长链。转移的时候只需要把i的所有儿子的f值+1中最大的赋值给f(i),次大的(不需要严格比f(i)小)赋值给g(i)。

然后我们就知道了根节点到树上任意一点的最长链。树上的每个点中MAX{g(i)+f(i)}即是直径。

然后我们需要做的是旋根操作。

如果我们已经知道了根i的f值,并且需要把根转给儿子j。则需要把j对i的f值影响删去再把i当作j的儿子,把i的f值+1与j的f值g值比较。然后就知道了j作为根时的f值与g值(变换后i的g值可能是错误的,但是不影响旋根,所以不需要特地维护)。

就这样遍历整颗树一遍,每个点在其本身的树上可以延伸的最长链f(i)的长度就可以算出来了。

时间复杂度为O(N+M)期望得分100%。

#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
using namespace std;
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define clr(x,c) memset(x,c,sizeof(x))
#define qwq(x) for(edge *o=head[x];o;o=o->next)
#define ll long long
int read(){
int x=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) x=x*10+c-'0',c=getchar();
return x;
}
const int nmax=2e5+5;
const int inf=0x7f7f7f7f;
int f[nmax],g[nmax];ll sm[nmax];
struct edge{
int to;edge *next;
};edge es[nmax<<1],*pt=es,*head[nmax];
void add(int u,int v){
pt->to=v;pt->next=head[u];head[u]=pt++;
pt->to=u;pt->next=head[v];head[v]=pt++;
}
void dfs(int x,int fa){
qwq(x) if(o->to!=fa){
dfs(o->to,x);
f[x]=max(f[x],f[o->to]+1);
}
}
void DFS(int x,int fa){
//printf("(%d %d)\n",x,fa);
int ta=-1,tb=-1,ca=0;
qwq(x) if(o->to!=fa) {
if(f[o->to]>ta) tb=ta,ta=f[o->to],ca=o->to;
else if(f[o->to]>tb) tb=f[o->to];
}
if(ta!=-1&&tb!=-1) ta+=2,tb+=2;
else if(ta<0&&tb<0) ta=0;
else tb=0;
qwq(x) if(o->to!=fa){
if(o->to!=ca) g[o->to]=max(g[x]+1,ta);
else g[o->to]=max(g[x]+1,tb);
}
qwq(x) if(o->to!=fa) DFS(o->to,x);
}
int find(int x,int r){
int l=0,ans=0,mid;
while(l<=r){
mid=(l+r)>>1;
if(f[mid]<=x) ans=mid,l=mid+1;
else r=mid-1;
}
return ans;
}
//二分的边界什么的总是写错。我开始是弄成g[0]=inf。然后f[mid]>=x 判断。。。然后Wa了三个点。要注意一下。
int main(){
freopen("connect.in","r",stdin);freopen("connect.out","w",stdout);
int n=read(),m=read(),u,v;
rep(i,1,n-1) u=read(),v=read(),add(u,v);
rep(i,1,m-1) u=read()+n,v=read()+n,add(u,v);
dfs(1,0);dfs(n+1,0);DFS(1,0);DFS(n+1,0); rep(i,1,n+m) g[i]=max(g[i],f[i]);
rep(i,1,m) f[i]=g[i+n];
sort(g+1,g+n+1);sort(f+1,f+m+1);
rep(i,1,m) sm[i]=sm[i-1]+f[i]; int mx=max(g[n],f[m]),cur;ll ans=0;
rep(i,1,n) {
cur=find(mx-g[i]-1,m);
ans+=1ll*cur*mx+1ll*(m-cur)*(g[i]+1)+sm[m]-sm[cur];
}
printf("%lld\n",ans);
fclose(stdin);fclose(stdout);
return 0;
}
/*
3 5
1 2
1 3
1 2
1 3
3 4
4 5
4+8+14=26 */

noip模拟赛#39的更多相关文章

  1. NOIP模拟赛20161022

    NOIP模拟赛2016-10-22 题目名 东风谷早苗 西行寺幽幽子 琪露诺 上白泽慧音 源文件 robot.cpp/c/pas spring.cpp/c/pas iceroad.cpp/c/pas ...

  2. contesthunter暑假NOIP模拟赛第一场题解

    contesthunter暑假NOIP模拟赛#1题解: 第一题:杯具大派送 水题.枚举A,B的公约数即可. #include <algorithm> #include <cmath& ...

  3. NOIP模拟赛 by hzwer

    2015年10月04日NOIP模拟赛 by hzwer    (这是小奇=> 小奇挖矿2(mining) [题目背景] 小奇飞船的钻头开启了无限耐久+精准采集模式!这次它要将原矿运到泛光之源的矿 ...

  4. 大家AK杯 灰天飞雁NOIP模拟赛题解/数据/标程

    数据 http://files.cnblogs.com/htfy/data.zip 简要题解 桌球碰撞 纯模拟,注意一开始就在袋口和v=0的情况.v和坐标可以是小数.为保险起见最好用extended/ ...

  5. 队爷的讲学计划 CH Round #59 - OrzCC杯NOIP模拟赛day1

    题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的讲学计划 题解:刚开始理解题意理解了好半天,然后发 ...

  6. 队爷的Au Plan CH Round #59 - OrzCC杯NOIP模拟赛day1

    题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的Au%20Plan 题解:看了题之后觉得肯定是DP ...

  7. 队爷的新书 CH Round #59 - OrzCC杯NOIP模拟赛day1

    题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的新书 题解:看到这题就想到了 poetize 的封 ...

  8. CH Round #58 - OrzCC杯noip模拟赛day2

    A:颜色问题 题目:http://ch.ezoj.tk/contest/CH%20Round%20%2358%20-%20OrzCC杯noip模拟赛day2/颜色问题 题解:算一下每个仆人到它的目的地 ...

  9. CH Round #52 - Thinking Bear #1 (NOIP模拟赛)

    A.拆地毯 题目:http://www.contesthunter.org/contest/CH%20Round%20%2352%20-%20Thinking%20Bear%20%231%20(NOI ...

随机推荐

  1. GXU - 7D - 区间求和 - 前缀和

    https://oj.gxu.edu.cn/contest/7/problem/D 描述 有一个所有元素皆为0的数组A,有两种操作: 1 l r x表示将A区间[l,r]内所有数加上x: 2 l r表 ...

  2. oracle数据库rownum讲解(转)

    https://blog.csdn.net/qq_40794266/article/details/78698321

  3. Cogs 1264. [NOIP2012] 开车旅行(70分 暴力)

    1264. [NOIP2012] 开车旅行 ★★☆   输入文件:drive.in   输出文件:drive.out   简单对比时间限制:2 s   内存限制:128 MB [题目描述] 小A 和小 ...

  4. 今天来记录一下关于ajax跨域的一些问题。以备不时之需。

    今天来记录一下关于ajax跨域的一些问题.以备不时之需. 跨域 同源策略限制 同源策略阻止从一个域上加载的脚本获取或操作另一个域上的文档属性.也就是说,受到请求的 URL 的域必须与当前 Web 页面 ...

  5. Jmeter分布式(转)jmeter -n -t baidu.jmx -l result.jtl -R 172.16.20.146:1099

    1.准备2台在同一个局域网内的机器,一台作为master主控机,一台作为slave 执行机 master机器ip:172.16.20.134 slave机器ip:172.16.20.146 2.在2台 ...

  6. js千分位处理

    一.去掉千分位 function removeThousands(num) { var x = num.split(','); return parseFloat(x.join("" ...

  7. vue——踩坑

    打包的时候,要记得改一下这个配置路径~ 教程:https://www.cnblogs.com/wanf/p/7871787.html

  8. UnityError 打包到Android错误解决

  9. 迅雷笔试题 (JAVA多线程)启动三个线程,分别打印A B C,现在写一个程序 循环打印ABCABCABC

    题目:http://wenku.baidu.com/view/d66187aad1f34693daef3e8a.html 启动三个线程,分别打印A B C,现在写一个程序 循环打印ABCABCABC. ...

  10. Notepad++代码函数快速提示设置

    设置——首选项——自动完成