2022NOIPA层联测18
B. 刷墙(b)
刷墙:
WA的原因是:我让每个数试图插入他之前的任意位置,但其实这个区间不可以任意划分
本来就存在的前后关系可能被打乱,被覆盖的在i之上,没被覆盖的在i之下,就假了。。
但我枚举时间顺序那个不至于错吧,好吧,它对了
可是为什么可以区间dp,大小区间并不可以累加吧
通过统计区间包含的区间个数然后判断,到底统计的是区间的个数还是颜色的个数?
f[l][r]只考虑被完全包含的小区间,没有跨越端点的应该可以合并了。。
题目说l小于r,那么长度为1的区间是不存在了,可是先放的[x, x+1]又被覆盖了怎么办?
要不然先改T3?
关于题意理解:从第li米到第ri米,所以li指的是点而不是一段长度的区间!?
所以l小于r这件事就好理解了。。。
良心新数据,成功地把我卡了:
3
1 4
1 2
3 4
所以暴力怎么写。。。每个点就代表他之后的一段就好了
TLE+假做法=27pts
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 303;
int n, c[maxn<<1], ans, ls[maxn<<1], cnt, res, d[maxn<<1], rem[maxn<<1];
bool vis[maxn];
set<int> s;
inline int read()
{
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9')
{
if(ch == '-')
{
f = -1;
}
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
x = (x << 1) + (x << 3) + (ch^48);
ch = getchar();
}
return x * f;
}
struct node
{
int l, r;
}p[maxn];
void check(int num, int m, int l, int r, int col)
{
s.clear();
for(int i=1; i<=m; i++)
{
if(num & (1<<i-1)) s.insert(i);
}
memcpy(d, c, sizeof(c));
for(int i=l; i<=r; i++)
{
if(s.find(d[i]) != s.end()) continue;
d[i] = col;
}
int yys = 0;
for(int i=1; i<=n; i++) vis[i] = 0;
for(int i=1; i<=cnt; i++) vis[d[i]] = 1;
for(int i=1; i<=n; i++) if(vis[i]) yys++;
if(yys <= res) return;
memcpy(rem, d, sizeof(rem));
res = yys;
}
int a[12];
inline bool query(int l, int r)
{
for(int i=l; i<=r; i++) if(c[i] == 0) return true;
return false;
}
inline void update(int l, int r, int col)
{
for(int i=l; i<=r; i++) if(!c[i]) c[i] = col;
}
void solve()
{
for(int i=1; i<=n; i++) a[i] = i;
do
{
int res = 0;
for(int i=1; i<=cnt; i++) c[i] = 0;
for(int i=1; i<=n; i++)
{
for(int j=p[a[i]].l; j<p[a[i]].r; j++)
{
c[j] = i;
}
}
for(int i=1; i<=n; i++) vis[i] = 0;
for(int i=1; i<=cnt; i++) vis[c[i]] = 1;
for(int i=1; i<=n; i++) if(vis[i]) res++;
ans = max(ans, res);
}while(next_permutation(a+1, a+1+n));
printf("%d\n", ans);
exit(0);
}
int main()
{
freopen("b.in", "r", stdin);
freopen("b.out", "w", stdout);
n = read();
for(int i=1; i<=n; i++)
{
p[i].l = read(); p[i].r = read();
ls[++cnt] = p[i].l; ls[++cnt] = p[i].r;
}
sort(ls+1, ls+1+cnt); cnt = unique(ls+1, ls+1+cnt)-ls-1;
for(int i=1; i<=n; i++)
{
int l = p[i].l, r = p[i].r;
p[i].l = lower_bound(ls+1, ls+1+cnt, l)-ls;
p[i].r = lower_bound(ls+1, ls+1+cnt, r)-ls;
}
if(n <= 10) solve();
for(int i=1; i<=n; i++)
{
int Max = 1 << i-1; res = 0;
for(int j=0; j<Max; j++)
{
check(j, i-1, p[i].l, p[i].r, i);
}
if(res > ans) memcpy(c, rem, sizeof(rem)), ans = res;
}
ans = 0;
for(int i=1; i<=n; i++) vis[i] = 0;
for(int i=1; i<=cnt; i++) vis[c[i]] = 1;
for(int i=1; i<=n; i++) if(vis[i]) ans++;
printf("%d\n", ans);
return 0;
}
所以解决最后一段是否重复的问题只需要把前缀和再减回去,check一下[k, k+1]是不是可以完全包含某区间
code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 603;
int n, ans, ls[maxn], cnt, f[maxn][maxn], sum[maxn][maxn];
inline int read()
{
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9')
{
if(ch == '-')
{
f = -1;
}
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
x = (x << 1) + (x << 3) + (ch^48);
ch = getchar();
}
return x * f;
}
struct node
{
int l, r;
}p[303];
int get(int l1, int l2, int r1, int r2)
{
return sum[l2][r2] - sum[l1-1][r2] - sum[l2][r1-1] + sum[l1-1][r1-1];
}
int main()
{
freopen("b.in", "r", stdin);
freopen("b.out", "w", stdout);
n = read();
for(int i=1; i<=n; i++)
{
p[i].l = read(); p[i].r = read();
ls[++cnt] = p[i].l; ls[++cnt] = p[i].r;
}
sort(ls+1, ls+1+cnt); cnt = unique(ls+1, ls+1+cnt)-ls-1;
for(int i=1; i<=n; i++)
{
int l = p[i].l, r = p[i].r;
p[i].l = lower_bound(ls+1, ls+1+cnt, l)-ls;
p[i].r = lower_bound(ls+1, ls+1+cnt, r)-ls;
}
for(int i=1; i<=n; i++)
{
sum[p[i].l][p[i].r]++;
}
for(int i=1; i<=cnt; i++)
{
for(int j=1; j<=cnt; j++)
{
sum[i][j] = sum[i][j]-sum[i-1][j-1]+sum[i-1][j]+sum[i][j-1];
}
}
for(int len=1; len<=cnt; len++)
{
for(int l=1,r; (r=l+len-1)<=cnt; l++)
{
for(int k=l; k<r; k++)
{
f[l][r] = max(f[l][r], f[l][k]+f[k+1][r]+(get(l,k,k+1,r)>0));
}
}
}
printf("%d\n", f[1][cnt]);
return 0;
}
C. 重复(c)
重复:
我好奇000010是怎么被我算成合法解的。。
取substr的时候算错数了。。还有一个上界设错了
然而用string函数比较的复杂度似乎并不对,改成hash会快一点,不过细节变多了。。比如下标的相对关系不能变
不过hash真的是比string快了不是一点半点!!!
https://www.cnblogs.com/Catherine2006/p/16758108.html
好像早就发现过这个结论
TLE 27
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 303;
string s1;
int n, m, ans;
inline int read()
{
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9')
{
if(ch == '-')
{
f = -1;
}
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
x = (x << 1) + (x << 3) + (ch^48);
ch = getchar();
}
return x * f;
}
inline void check(string s)
{
n = s.size(); //int n1 = n / 3 + 1, n2 = (n - n1) / 2;
for(int i=1; i<=n; i++)
{
string a = s.substr(0, i), b = s.substr(i, i);
//printf("i = %d\n", i);
if(a != b) continue;
for(int j=1; j<=n; j++)
{
if(n - j - i <= i + i + j) continue;//这个等号并没有问题。。
//printf("n-j = %d i+i = %d j = %d\n", n-j, i+i, j);
string f = s.substr(n-j, j), c = s.substr(i+i, j);
if(c != f) continue;
//printf("n-j-i+1 = %d i = %d\n", n-j-i+1, i);
string e = s.substr(n-j-i, i);
if(a != e) continue;
//cout << a << " " << b << " " << c << " " << e << " " << f << endl;
ans++;
//printf("ans = %d\n", ans);
}
}
}
int main()
{
freopen("c.in", "r", stdin);
freopen("c.out", "w", stdout);
cin >> s1;
//string s = "000110";
//check(s);
m = s1.size();
for(int len=6; len<=m; len++)
{
for(int i=0; i+len-1<m; i++)
{
//printf("i = %d len = %d\n", i, len);
string s = s1.substr(i, len);
//cout << s << endl;
check(s);
}
}
printf("%d\n", ans);
return 0;
}
TLE 55
// ubsan: undefined
// accoders
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 5007;
string s1;
int n, m, ans;
ull h[maxn], jc[maxn];
inline int read()
{
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9')
{
if(ch == '-')
{
f = -1;
}
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
x = (x << 1) + (x << 3) + (ch^48);
ch = getchar();
}
return x * f;
}
inline ull gethash(int l, int r)
{
if(l == 0) return h[r];
return h[r] - h[l-1] * jc[r-l+1];
}
inline void check(int l, int n)
{
for(int i=1; i<=n; i++)
{
if(gethash(l, l+i-1) != gethash(l+i, l+i+i-1)) continue;
for(int j=1; j<=n; j++)
{
if(n - j - i <= i + i + j) continue;
if(gethash(l+n-j, l+n-1) != gethash(l+i+i, l+i+i+j-1)) continue;
if(gethash(l, l+i-1) != gethash(l+n-j-i, l+n-j-1)) continue;
//cout << s1.substr(l, i) << " " << s1.substr(l+i, i) << " " << s1.substr(l+i+i, j) << " " << s1.substr(l+n-j-i, i) << " " << s1.substr(l+n-j, j) << endl;
ans++;
}
}
}
void init()
{
h[0] = s1[0] - '0' + 1;
for(int i=1; i<m; i++)
{
h[i] = h[i-1] * 131 + s1[i] - '0' + 1;
}
jc[0] = 1;
for(int i=1; i<=m; i++)
{
jc[i] = jc[i-1] * 131;
}
}
int main()
{
freopen("c.in", "r", stdin);
freopen("c.out", "w", stdout);
cin >> s1;
m = s1.size();
init();
for(int len=6; len<=m; len++)
{
for(int i=0; i+len-1<m; i++)
{
//string s = s1.substr(i, len);
//check(s);
check(i, len);
}
}
printf("%d\n", ans);
return 0;
}
At last,根据AABCAB预处理一下AB的个数,用hash判断AA
code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 5007;
int n;
char s[maxn];
ll cnt[maxn][maxn], ans;
ull h[maxn], jc[maxn];
map<ull, ll> mp;
inline int read()
{
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9')
{
if(ch == '-')
{
f = -1;
}
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
x = (x << 1) + (x << 3) + (ch^48);
ch = getchar();
}
return x * f;
}
inline ull gethash(int l, int r)
{
return h[r] - h[l-1] * jc[r-l+1];
}
int main()
{
freopen("c.in", "r", stdin);
freopen("c.out", "w", stdout);
scanf("%s", s+1);
n = strlen(s+1);
h[1] = s[1] - '0';
for(int i=2; i<=n; i++)
{
h[i] = h[i-1] * 131 + s[i] - '0';
}
jc[0] = 1;
for(int i=1; i<=n; i++)
{
jc[i] = jc[i-1] * 131;
}
for(int len=1; len<=n; len++)
{
mp.clear();
for(int l=n-len+1; l>=1; l--)
{
int r = l + len - 1;
if(mp.find(gethash(l, r)) != mp.end()) cnt[l][r] = mp[gethash(l, r)];
if(r+len<=n) mp[gethash(l+len, r+len)]++;
}
}
for(int i=1; i<=n; i++)
{
for(int j=n; j>=i; j--) cnt[i][j] += cnt[i][j+1];
}
for(int l=1; l<=n; l++)
{
for(int r=l+1; r<=n; r+=2)
{
int len = (r - l + 1) / 2;
if(gethash(l, l+len-1) != gethash(l+len, r)) continue;
ans += cnt[l+len][r+1];
}
}
printf("%lld\n", ans);
return 0;
}
时光花火,水月星辰