$第一次6题纪念$
A - Lexicographic Order
题意:
$s字符串的字典序是否小于t$
思路:
$模拟$
时间复杂度:$O1$
#include <bits/stdc++.h>
#define fer(i,a,b) for(re i = a ; i <= b ; ++ i)
#define der(i,a,b) for(re i = a ; i >= b ; -- i)
#define de(x) cout << x << "\n"
#define sf(x) scanf("%lld",&x)
#define pll pair<int,int>
#define re register int
#define int long long
#define pb push_back
#define y second
#define x first
using namespace std;
const int N = 1e6 + 10 , M = 2010 , inf = 0x3f3f3f3f , mod = 1e9 + 7 ;
signed main()
{
string s , t ;
cin >> s >> t ;
if(s < t) puts("Yes") ;
else puts("No") ;
return 0;
}
B - AtCoder Quiz
题意:
$给定4个不同的字符串$
$输入三个不同字符串,求没有出现过的那个$
思路:
$模拟$
时间复杂度:$O1$
#include <bits/stdc++.h>
#define fer(i,a,b) for(re i = a ; i <= b ; ++ i)
#define der(i,a,b) for(re i = a ; i >= b ; -- i)
#define de(x) cout << x << "\n"
#define sf(x) scanf("%lld",&x)
#define pll pair<int,int>
#define re register int
#define int long long
#define pb push_back
#define y second
#define x first
using namespace std;
const int N = 1e6 + 10 , M = 2010 , inf = 0x3f3f3f3f , mod = 1e9 + 7 ;
map<string,int> q ;
signed main()
{
string x ;
q["ABC"] ++ ;
q["ARC"] ++ ;
q["AGC"] ++ ;
q["AHC"] ++ ;
for(int i = 1 ; i <= 3 ; i ++)
{
cin >> x ;
q[x] ++ ;
}
for(auto i : q)
{
if(i.y == 1)
{
cout << i.x << "\n" ;
break ;
}
}
return 0;
}
C - Inverse of Permutation
题意:
$给定一个n的排列$
$求对所有的[1 <= i <= n ] 等于i的下标$
思路:
$模拟$
时间复杂度:$On$
#include <bits/stdc++.h>
#define fer(i,a,b) for(re i = a ; i <= b ; ++ i)
#define der(i,a,b) for(re i = a ; i >= b ; -- i)
#define de(x) cout << x << "\n"
#define sf(x) scanf("%lld",&x)
#define pll pair<int,int>
#define re register int
#define int long long
#define pb push_back
#define y second
#define x first
using namespace std;
const int N = 1e6 + 10 , M = 2010 , inf = 0x3f3f3f3f , mod = 1e9 + 7 ;
int n ;
int a[N] ;
int q[N] ;
signed main()
{
cin >> n ;
fer(i,1,n) sf(a[i]) ;
fer(i,1,n)
{
q[a[i]] = i ;
}
fer(i,1,n)
{
cout << q[i] << " " ;
}
return 0;
}
D - Cutting Woods
题意:
$一开始有一根木棒$
$长度为n$
$从1到n编号$
$输入q个操作$
$操作1$
$断开x所在的木棒$
$[1,n] 断开x变成了 [1,x] [x+1,n]$
$操作2$
$询问x所在的区间长度$
$q <= 1e5$
$n <= 1e9$
$1 <= x <= 1e9$
思路:
$有个很重要的性质$
$分割之后左边以及右边这个区间的答案是固定的$
$也就是说答案只跟分割点有关$
$比如区间[l,r] 分割x变成了[l,x] , [x+1,r]$
$可以发现$
$l到x这个区间的询问答案都是x-l+1$
$x+1到r这个区间的询问答案都是r-(x + 1) - 1$
$所以可以考虑二分找到所在区间相邻2个的分割点下标$
$先考虑边界问题$
$边界无非是0 - n + 1 / 0 - n / 1 - n / 1 - n + 1$
$这4种的其中一种$
$这个时候先假设区间是[1,2] , [3,4] , [5]$
分割点是 0/1 2 4 5/5+1
对于查询2
找到第一个大于等于2的数是2
第一个小于2的数应该是 0/1
答案是2
所以应该是 2 - 0 = 2
左边界应该是0在考虑查询5
答案是1
找到第一个大于等于5的数是5/6
第一个小于5的数应该是4
所以应该是 5 - 4 = 1
右边界是n在考虑二分操作的时候 分割点数组保持有序
所以可以用set动态维护
时间复杂度:$Onlogn$
#include <bits/stdc++.h>
#define fer(i,a,b) for(re i = a ; i <= b ; ++ i)
#define der(i,a,b) for(re i = a ; i >= b ; -- i)
#define de(x) cout << x << "\n"
#define sf(x) scanf("%lld",&x)
#define pll pair<int,int>
#define re register int
#define int long long
#define pb push_back
#define y second
#define x first
using namespace std;
const int N = 1e6 + 10 , M = 2010 , inf = 0x3f3f3f3f , mod = 1e9 + 7 ;
set<int> q ;
int n , t ;
signed main()
{
cin >> n >> t ;
q.insert(0) ;
q.insert(n) ;
while(t--)
{
int c , x ;
sf(c) , sf(x) ;
if(c == 1)
{
q.insert(x) ;
}
else
{
cout << *q.lower_bound(x) - *--q.lower_bound(x) << "\n" ;
}
}
return 0;
}
E - Sorting Queries
题意:
$一开始有一个空的序列$
$q个操作$
$操作1$
$在序列末尾添加一个数x$
$操作2$
$输出序列第一个数并且删除$
$操作3$
$给当前序列排序$
$q <= 1e5$
$x <= 1e9$
思路:
$假设不考虑操作3$
$可以用数组模拟队列on解决$
$那么队列是一定要使用的$
$现在考虑一下怎么维护操作3对队列的影响$
$队列的2个元素$
$hh代表对头$
$tt代表队尾$
$排序如果暴力的话On^2logn$
$考虑如何优化$
$有一个很重要的性质是排序的时候$
$是边插入边排序$
$所以可以用set动态维护$
$然后把对头指向set后面的第一个下标$
时间复杂度:$Onlogn$
#include <bits/stdc++.h>
#define fer(i,a,b) for(re i = a ; i <= b ; ++ i)
#define der(i,a,b) for(re i = a ; i >= b ; -- i)
#define de(x) cout << x << "\n"
#define sf(x) scanf("%lld",&x)
#define pll pair<int,int>
#define re register int
#define int long long
#define pb push_back
#define y second
#define x first
using namespace std;
const int N = 1e6 + 10 , M = 2010 , inf = 0x3f3f3f3f , mod = 1e9 + 7 ;
int a[N] ;
multiset<int> q ;
// 带重复元素的set
bool st[N] ;
signed main()
{
int hh = 0 , tt = 0 ;
int t ;
cin >> t ;
int k = 1; // k = 1 表示队列第一个数的下标是1
int op ;
while(t--)
{
sf(op) ;
if(op == 1)
{
int x ;
sf(x) ;
a[++ tt] = x ;
// 队尾加入x
}
else if(op == 2)
{
// 如果排序过
if(q.size())
{
cout << *q.begin() << "\n" ;
q.erase(q.begin()) ;
// 输入对头并且删除
}
else
{
cout << a[k] << "\n" ;
st[k] = 1 ;
k ++ ;
// 没有排序过就输出第一个数
// 然后标记这个数没有了
// 对头 ++
}
}
else
{
for(int i = k ; i <= tt ; i ++)
{
if(!st[i]) q.insert(a[i]) ;
}
k = tt + 1 ;
// 插入之后 对头指向队尾的下一个下标
}
}
return 0;
}
G - Groups
题意:
$有1,2,3......n$
$n个数$
$问这n个数可以分为多少组$
$并且保证每一组的数modm的值没有相等的$
$输出每个组的方案$
$n <= 5000$
思路:
$假设先不考虑保证每一组的数modm的值没有相等的$
$那么就是一个很经典的第二类斯特林数$
$f[i][j]表示前i个数分成j组的方案数$
$f[i][j] = f[i-1][j-1] +j*f[i-1][j]$
$第i个数单独分成一组是f[i-1][j-1]$
$或者第i个数分成前面已经有的j组中的其中一组j * f[i-1][j]$
$那么考虑一下加上题目给的限制条件$
$每一组的数modm的值没有相等的$
$也就是说第i个数分成前面已经有的j组中的其中一组$
$必须保证分到的那个组中没有当前这个数modm的值出现$
$所以先维护一个cnt数组$
$表示a[i] mod m的个数$
$在放第i个数的时候如果已经放过了这个数了$
$放下一个数的时候就不能在放这个数$
$所以状态方程就变成了$
$f[i][j] = f[i-1][j-1] +k*f[i-1][j]$
$但是这样还是有一个问题$
$第一层循环枚举的是i也就是这个数$
$第二层循环枚举的是j组数$
$我们发现不能不重不漏的进行转移$
$因为必须保证每个数是按照顺序放的$
$所以先枚举组数j$
$在枚举i$
$在组数固定情况下$
$依次放入每个数即可$
$k的求法具体细节可以看代码$
时间复杂度:$On^2$
#include <bits/stdc++.h>
#define fer(i,a,b) for(re i = a ; i <= b ; ++ i)
#define der(i,a,b) for(re i = a ; i >= b ; -- i)
#define de(x) cout << x << "\n"
#define sf(x) scanf("%lld",&x)
#define pll pair<int,int>
#define re register int
#define int long long
#define pb push_back
#define y second
#define x first
using namespace std;
const int N = 1e6 + 10 , M = 5010 , inf = 0x3f3f3f3f , mod = 998244353 ;
int f[M][M] ;
// 前i个数分成j组的方案数
int n , m ;
int a[N] ;
// 1到i的每个数
int cnt[M] ;
// 每个数 % m的个数
int q[M] ;
// 工具数组
signed main()
{
cin >> n >> m ;
fer(i,1,n)
{
a[i] = i ;
cnt[i % m] ++ ;
}
f[0][0] = 1 ; // 初始化
for(int j = 1 ; j <= n ; j ++)
{
// 每次固定j组数
memcpy(q,cnt,sizeof cnt) ;
// 把cnt数组给q数组
for(int i = 1 ; i <= n ; i ++)
{
f[i][j] = (f[i-1][j-1] + f[i-1][j] * (j - ( cnt[a[i] % m] - q[a[i] % m] ) )) % mod;
// k = j - ( cnt[a[i] % m] - q[a[i] % m] )
// 表示用j所有组减去前面有多少个组放了这个数 % m
q[a[i] % m] -- ;
// 放了这个数之后 这个数 % m --
// 表示j之前的所有组中放了a[i] % m 的组 ++
}
}
for(int i = 1 ; i <= n ; i ++) cout << f[n][i] % mod << "\n" ;
return 0;
}
大佬orz!!!
tql
orz
orz
太强了
很强