HGOI 20200804
T1 排序(sort)
答案就是有逆序对的元素个数
因为可以把有逆序对的元素从大到小操作一遍就行
\(O(nlogn)\)
好像还有 \(O(n)\) 做法 orz
#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define per(i, a, b) for (int i = a; i >= b; i--)
#define siz(a) (int)a.size()
#define pb push_back
#define mp make_pair
#define ll long long
#define fi first
#define se second
const int N = 5000010 ;
int n, ans ;
int bit[N], a[N], dp[N] ;
void mdf(int p, int v) {
for (; p <= n; p += p & -p) bit[p] = max(bit[p], v) ;
}
int ask(int p) {
int ans = 0 ;
for (; p; p -= p & -p) ans = max(ans, bit[p]) ;
return ans ;
}
char Getchar() {
static char buf[100000], *S = buf, *T = buf ;
if (S == T) {
S = buf ;
T = S + fread(buf, 1, 100000, stdin) ;
if (S == T) return EOF ;
}
return *S++ ;
}
int read() {
int f = 1, x = 0 ;
char ch = Getchar() ;
while (!isdigit(ch)) { if (ch == '-') f = -1 ; ch = Getchar() ; }
while (isdigit(ch)) { x = x * 10 + ch -'0' ; ch = Getchar() ; }
return x * f ;
}
signed main() {
freopen("sort.in", "r", stdin) ;
freopen("sort.out", "w", stdout) ;
n = read() ;
rep(i, 1, n) a[i] = read() ;
memset(bit, 0, sizeof(bit)) ;
per(i, n, 1) {
if (ask(a[i] - 1) == 1) {
// cout<<i<<endl;
ans++ ;
}
mdf(a[i], 1) ;
}
printf("%d\n", ans) ;
return 0 ;
}
T2 图(graph)
bitset
枚举 \(v\) 得到 \(u\) 的集合 \(U\) 和 \(w\) 的集合 \(W\)
然后要求就是所有的 \((u,x)\) 的 \(x\) 属于 \(W\)
使用 \(bitset\) 暴力
时间复杂度 \(O(n^3/64)\)
因为跑不满,实测很快,十几毫秒飞速过
#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define per(i, a, b) for (int i = a; i >= b; i--)
#define siz(a) (int)a.size()
#define pb push_back
#define mp make_pair
#define ll long long
#define fi first
#define se second
const int N = 2030 ;
int n ;
char s[N] ;
bitset <N> tr[N], tb[N], w ;
vector <int> u, b[N], ib[N], r[N], ir[N] ;
bool solve(vector <int> R[N], vector <int> IR[N], bitset <N> T[N]) {
rep(v, 1, n) {
// cout<<v<<endl;
// if (!siz(ir[v]) || !siz(r[v])) continue ;
u.clear() ;
w.reset() ;
rep(i, 0, siz(IR[v]) - 1) u.pb(IR[v][i]) ;
rep(i, 0, siz(R[v]) - 1) w[R[v][i]] = 1 ;
rep(i, 0, siz(u) - 1) {
// cout<<u[i]<<endl;
// rep(j, 1, 4) cout << T[u[i]][j] << " " ; cout << endl ;
// rep(j, 1, 4) cout << w[j] << " " ; cout << endl ;
int U = u[i] ;
bitset <N> tmp ;
tmp = T[U] | w ;
// rep(j, 1, 4) cout << tmp[j] << " " ; cout << endl ;
if (tmp != T[U]) return false ;
}
//cout<<"ok\n";
}
return true ;
}
signed main() {
// freopen("graph.in", "r", stdin) ;
// freopen("graph.out", "w", stdout) ;
int t ; scanf("%d", &t) ;
while (t--) {
scanf("%d", &n) ;
rep(i, 1, n) r[i].clear(), ir[i].clear(), b[i].clear(), ib[i].clear(), tr[i].reset(), tb[i].reset() ;
rep(i, 1, n) {
scanf("%s", s) ;
rep(j, 1, n)
if (s[j - 1] != 'U') {
if (s[j - 1] == 'R') r[i].pb(j), ir[j].pb(i), tr[i][j] = 1 ;
else b[i].pb(j), ib[j].pb(i), tb[i][j] = 1 ;
}
}
int ans = 1 ;
ans &= solve(r, ir, tr) ;
if (ans) ans &= solve(b, ib, tb) ;
puts(ans ? "T" : "N") ;
}
return 0 ;
}
T3 或(or)
数位dp
这种东西NOIP是不可能考的(flag)
搬题解
\(f(i,j,k)\) 表示计算到第 \(i\) 位,当前 \(r\) 是否取到上界,\(l\) 是否取到上界 \((k)\) 的状态下的答案,\(g(i,j,k)\) 表示方案数
时间复杂度 \(O(len)\) 大概是 \(10^6\)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1010000,mod = 1e9+7;
int f[N][2][2],g[N][2][2],c[N],len,n;
int add(int x,int y){x += y;if (x >= mod) x -= mod;return x;}
int cal(int,int,int);
int read(){
int x = 0;char ch = getchar();
while (ch < '0' || '9' < ch) ch = getchar();
return ch - '0';
}
int main(){
freopen("or.in","r",stdin);
freopen("or.out","w",stdout);
scanf("%d",&n);
for (int i = n;i >= 1;i--) c[i] = read();
len = n;
memset(f,0,sizeof(f));
memset(g,0,sizeof(g));
f[len+1][1][1] = 0;
g[len+1][1][1] = 1;
for (int i = len;i >= 1;i--){
for (int j = 0;j < 2;j++)
for (int k = 0;k < 2;k++)
if (g[i+1][j][k]){
for (int a = 0;a < 2;a++)
for (int b = 0;b < 2;b++){
int u = cal(c[i],j,a),v = cal(a,k,b);
if (u != -1 && v != -1){
if (a|b) {
f[i][u][v] = add(f[i][u][v],add(f[i+1][j][k],g[i+1][j][k]));
g[i][u][v] = add(g[i][u][v],g[i+1][j][k]);
}
else{
f[i][u][v] = add(f[i][u][v],f[i+1][j][k]);
g[i][u][v] = add(g[i][u][v],g[i+1][j][k]);
}
}
}
}
}
int ans = 0;
for (int i = 0;i < 2;i++)
for (int j = 0;j < 2;j++)
ans = add(ans,f[1][i][j]);
printf("%d\n",ans);
return 0;
}
int cal(int x,int y,int z){
if (y == 1 && z == x) return 1;
if (y == 1 && z > x) return -1;
if (y == 1 && z < x) return 0;
if (y == 0) return 0;
}
加油ヾ(◍°∇°◍)ノ゙