08-11 NOIP模拟测试17

期望得分:75+?+(24+?rand)

实际得分:60+55+24

没有把期望拿满

今天忘了在考试前调gedit,然后考试的时候没默下来,心态爆炸的不行。。。

才发现之前自己一直忘了用c++11提交,蓝瘦。

A. 入阵曲

暴力n^4+特性可得75,然而由于我的智障测试点分治阀很shi以及没有开longlong也没取模只有60分。。。

像这种数据范围只给<=不确定具体范围而不好卡分治时,可以用输入量先算下复杂度,然后用计算量分治。对于这题算下n*m>6400 n^4够呛 跑特性即可。

正解:

看这数据范围正解应该是n^3的,所以我们要去掉一层枚举。

这题答案爆long long,++ans必死。所以我们要一次拿出多个答案,就是+=。

哪里有+=成段操作,线段树?加个log好像就T了。。。

天天爱跑酷?好像差不多,我们可以用类似的思想,不用对于每个答案都走一遍流程,而可以只走一遍,巧妙地在整体的计算过程中不断得到当时已经可以得到的局部答案。

那题的过程体现在桶上,这题是否也可?

然后引入一个十分关键而我考场上压根没往这想的性质:

 

不得不说这真的是太帅了。真没想到哇,看来我还是菜啊。

把这个性质拓展到二维也是类似的。每次枚举两个行n^2(就是x1,x2),然后向右O(m)扫,过程中维护桶存x1~x2卡着的横向前缀和。由于k很大,不能够最后处理桶里的答案,所以在过程中实时统计。最后删除不能memset,怎么来怎么回去就好。

 1 #include<cstdio>
 2 #include<cstring>
 3 #define ll long long
 4 #define reg register
 5 #define F(i,a,b) for(register int (i)=(a);(i)<=(b);++(i))
 6 using namespace std;
 7 const int N=405,G=1000005;
 8 int read();
 9 int z[N][N];
10 int sum[N][N];
11 int bk[G];
12 int n,m,g;
13 int get(int i,int j,int k,int l)
14 {
15     return ((sum[k][l]-sum[i-1][l]-sum[k][j-1]+sum[i-1][j-1])%g+g)%g;
16 }
17 int main()
18 {
19     n=read(); m=read(); g=read();
20     F(i,1,n)
21     {
22         F(j,1,m)
23         {
24             z[i][j]=read();
25             sum[i][j]=((sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1])%g+z[i][j]+g)%g;
26         }
27     }
28     ll ans=0;
29     reg int t;
30     F(i,1,n)
31     {
32         F(j,i,n)
33         {
34             F(k,1,m)
35             {
36                 t=get(i,1,j,k);
37                 ans+=bk[t];
38                 ++bk[t];
39             }
40             ans+=bk[0];
41             F(k,1,m) --bk[get(i,1,j,k)];
42         }
43     }
44     printf("%lld
",ans);
45     return 0;
46 }
47 int read()
48 {
49     int x=0;
50     char tc=getchar();
51     while(tc<'0'||tc>'9') tc=getchar();
52     while(tc>='0'&&tc<='9') x=x*10+tc-48,tc=getchar();
53     return x;
54 }
View Code

B. 将军令

刚看觉得是一道很nb的dp题,只会k==1的类小胖守皇宫。

然后发现似乎可以贪心,想了下觉得是正确的。然而我充分不相信我觉得,于是觉得贪心不是正解,但能拿到不少分。

于是放弃了一堆分类讨论的dp,开始码一个不走心的贪心dfs。

码完就发现了问题,发现在处理祖先链上的子孙时有点bug。

说正解吧:真是贪心

发现对于一个没有被控制的点,在它的k级祖先驻队一定是最优的。假设我们将小队下调,那么子孙一定还能被控制,而祖先方向的控制范围-1,答案变差。

钦定一个节点做根,我们把所有节点的深度从大到小排序,这可以用bfs来O(n)做,也可以得深度排序或者优先队列加个logn。

然后扫,对于一个没有被控制的点,++ans,向上找k级祖先,然后从k级祖先暴力dfs走k步控制周围点,重复这个过程。根节点注意特判。

由于k很小可做,复杂度为O(kn)。

  1 #include<cstdio>
  2 #include<vector>
  3 #include<queue>
  4 #include<algorithm>
  5 #include<cstdlib>
  6 #define ll long long
  7 #define reg register
  8 #define F(i,a,b) for(register int (i)=(a);(i)<=(b);++(i))
  9 using namespace std;
 10 int read();
 11 const int N=100005;
 12 int n,d,typ;
 13 bool vis[N],cl[N];
 14 int fa[N];
 15 vector<int> p;
 16 queue<int> q;
 17 struct R{
 18     int u,v,next;
 19 }r[N<<1];
 20 int fir[N],o=1;
 21 void add(int u,int v)
 22 {
 23     r[++o].u=u;
 24     r[o].v=v;
 25     r[o].next=fir[u];
 26     fir[u]=o;
 27 }
 28 void bfs()
 29 {
 30     q.push(1);
 31     int u,v;
 32     while(!q.empty())
 33     {
 34         u=q.front();
 35         q.pop();
 36         p.push_back(u);
 37         vis[u]=1;
 38         for(reg int i=fir[u];i;i=r[i].next)
 39         {
 40             v=r[i].v;
 41             if(vis[v]) continue;
 42             fa[v]=u;
 43             q.push(v);
 44         }
 45     }
 46 }
 47 void dfs(int u,int fa,int step)
 48 {
 49     cl[u]=1;
 50     if(step==d) return;
 51     for(reg int i=fir[u];i;i=r[i].next)
 52     {
 53         int v=r[i].v;
 54         if(v==fa) continue;
 55         dfs(v,u,step+1);
 56     }
 57 }
 58 int main()
 59 {
 60     n=read(); d=read(); typ=read();
 61     if(d==0)
 62     {
 63         printf("%d
",n);
 64         return 0;
 65     }
 66     int ta,tb;
 67     F(i,1,n-1)
 68     {
 69         ta=read(); tb=read();
 70         add(ta,tb); add(tb,ta);
 71     }
 72     reg int ans=0,x;
 73     bfs();
 74     for(reg int i=p.size()-1;i>=0;--i)
 75     {
 76         if(!cl[p[i]])
 77         {
 78             ++ans;
 79             x=p[i];
 80             F(o,1,d)
 81             {
 82                 if(!fa[x]) break;
 83                 x=fa[x];
 84             }
 85             dfs(x,0,0);
 86         }
 87     }
 88     printf("%d
",ans);
 89     return 0;
 90 }
 91 int read()
 92 {
 93     int x=0;
 94     char tc=getchar();
 95     while(tc<'0'||tc>'9') tc=getchar();
 96     while(tc>='0'&&tc<='9') x=x*10+tc-48,tc=getchar();
 97     return x;
 98 }
 99 /*
100 
101 g++ 2.cpp -o 2
102 ./2
103 4 1 0
104 1 2
105 1 3
106 1 4
107 
108 g++ 2.cpp -o 2
109 ./2
110 6 1 0
111 1 2
112 1 3
113 1 4
114 4 5
115 4 6
116 
117 
118 g++ 2.cpp -o 2
119 ./2
120 20 2 0
121 1 11
122 1 2
123 1 3
124 2 5
125 2 4
126 4 10
127 4 6
128 6 9
129 6 7
130 6 8
131 3 12
132 12 13
133 12 14
134 12 15
135 12 16
136 14 17
137 17 18
138 17 19
139 13 20
140 
141 */
View Code

C. 星空

T3日常神仙,也不是之前那种能卡过的T3。

这真的是道好题,

考场上只会bfs+状压暴力转移,24分。

说正解:神状压!

隐藏的十分隐蔽。不过这题非常综合,在通往真理的路上迷雾重重,都是高难思维点。

启发:在当前的问题无法着手时,不妨利用一些性质或者是技巧(平时积累)转化(当然是简化)题意,逐步击破!

阶段一:从扯淡题意中抽离模型。

给定一个n长的0/1串,m个区间长度(可重复使用),用最少的区间翻转n串,使n串全为1。

或者一种令我走进死胡同的说法:给定一个n长的0/1串,m个不同长度全1串,用最少的区间异或n串,使n串全为1。然后便能发现n串的0位有奇数个区间叠加,1位有偶数个区间叠加,然后我就开始YY什么01Trie、哈希表。emm...
在一种思路走不通的时候,如果超过自己的心态极限,不要犹豫换个角度,或先拿到部分分稳住。

阶段二:

是对于以往的大区间频繁修改问题,我们可以用差分转化为单点修改(或者直接线段树),异或也可以差分。

定义b[i]=a[i]^a[i-1],那么[l,r]的翻转在b的表现为b[l]与b[r+1]取反。

然后问题就转化为在n+1(多出的一个数处理边界)数中,用m个距离不同的1xxx1对异或使序列全为0(b[],全0即a[]全等,之所以n+1也是定义了等的是什么)。

似乎还是不可做。emm

阶段三:

我们发现答案中不会存在一个操作对于两个0。那么有以下理解:

1.异或到0 1,含义可理解为1走到0的位置。

2.1 1,两个1相遇相消。

对2k个点为起点分别bfs一遍,复杂度O(2kmn)

注意bfs左右都要走,例如一点在左,4长距离,5长和1长区间,显然是先右5再左1,而不是(右1)*4

要使所有物品消失,又k很小,考虑状压。

非常非常类似与愤怒的小鸟,直接状态刷表即可。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<vector>
  4 #include<queue>
  5 #include<algorithm>
  6 #include<cstdlib>
  7 #define ll long long
  8 #define reg register
  9 #define F(i,a,b) for(register int (i)=(a);(i)<=(b);++(i))
 10 using namespace std;
 11 //1亮0灭,异或差分,1不同
 12 //消1为0
 13 int read();
 14 const int N=40005;
 15 const int K=20;
 16 const int M=70;
 17 int n,need,m;
 18 int a[N],b[N],id[N],pos[K],len[M],cnt;
 19 int dis[K][K];
 20 bool vis[N];
 21 queue<pair<int,int> > q;
 22 struct OPT{
 23     int obj,w;
 24 }opt[N];
 25 int dp[1<<K];
 26 int ocnt;
 27 void bfs(int st)
 28 {
 29     memset(vis,0,sizeof(vis));
 30     q.push(make_pair(st,0));
 31     int u,v,sp;
 32     vis[st]=1;
 33     dis[id[st]][id[st]]=0;
 34     while(!q.empty())
 35     {
 36         u=q.front().first;
 37         sp=q.front().second;
 38         q.pop();
 39         if(id[u]&&dis[id[st]][id[u]]==-1)
 40         {
 41             dis[id[st]][id[u]]=sp;
 42         }
 43         F(i,1,m)
 44         {
 45             v=u+len[i];
 46             if(v<=n&&!vis[v])
 47             {
 48                 vis[v]=1;
 49                 q.push(make_pair(v,sp+1));
 50             }
 51             v=u-len[i];
 52             if(v>0&&!vis[v])
 53             {
 54                 vis[v]=1;
 55                 q.push(make_pair(v,sp+1));
 56             }
 57         }
 58     }
 59 }
 60 int main()
 61 {
 62     memset(dis,-1,sizeof(dis));
 63     n=read(); need=read(); m=read();
 64     F(i,1,n) a[i]=1;
 65     int t;
 66     F(i,1,need) a[read()]=0;
 67     a[0]=1;
 68     ++n;
 69     a[n]=1;
 70     F(i,1,n)
 71     {
 72         b[i]=a[i]^a[i-1];
 73         if(b[i])
 74         {
 75             id[i]=++cnt;
 76             pos[cnt]=i;
 77         }
 78     }
 79     F(i,1,m)
 80     {
 81         len[i]=read();
 82     }
 83     if(m==1)
 84     {
 85         int ans=0;
 86         F(i,1,n)
 87         {
 88             if(b[i])
 89             {
 90                 b[i]=0;
 91                 b[i+len[1]]^=1;
 92                 ++ans;
 93             }
 94         }
 95         printf("%d
",ans);
 96         return 0;
 97     }
 98     F(i,1,cnt) bfs(pos[i]);
 99     F(i,1,cnt)
100     {
101         F(j,i+1,cnt)
102         {
103             if(dis[i][j]==-1) continue;
104             opt[++ocnt].obj=(1<<(i-1))|(1<<(j-1));
105             opt[ocnt].w=dis[i][j];
106 //            printf("(%d->%d) %d
",i,j,dis[i][j]);
107         }
108     }
109     memset(dp,0x3f,sizeof(dp));
110     dp[0]=0;
111     const int S=(1<<cnt)-1;
112     for(reg int s=0;s<=S;++s)
113     {
114         F(i,1,ocnt)
115         {
116             dp[s|opt[i].obj]=min(dp[s|opt[i].obj],dp[s]+opt[i].w);
117         }
118     }
119     printf("%d",dp[S]);
120     return 0;
121 }
122 int read()
123 {
124     int x=0;
125     char tc=getchar();
126     while(tc<'0'||tc>'9') tc=getchar();
127     while(tc>='0'&&tc<='9') x=x*10+tc-48,tc=getchar();
128     return x;
129 }
View Code

最后  加油!qwq

原文地址:https://www.cnblogs.com/hzoi-yzh/p/11335874.html