(1)题目大意
问你第k个不出现4的数字是多少。
(2)解题思路
1.九进制,把每一位大于等于4的位置+1
2.二分+数位dp,二分第k个数,然后数位dp计算有多少个不含4的数即可。
(3)代码实现
#include <iostream>
#include <map>
#include <set>
#include <vector>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <stack>
#include <algorithm>
#include <cmath>
#include <unordered_map>
#include <deque>
#include <bitset>
#define rep(i,z,n) for(int i = z;i <= n; i++)
#define per(i,n,z) for(int i = n;i >= z; i--)
#define PII pair<int,int>
#define fi first
#define se second
#define vi vector<int>
#define vl vector<ll>
#define pb push_back
#define sz(x) (int)x.size()
#define all(x) (x).begin(),(x).end()
using namespace std;
using ll = long long;
const int N = 2e5 + 10;
ll dp[13];
int nums[N],cnt;
inline ll dfs(int pos,bool lim)
{
if(pos == -1) return 1;
if(!lim && dp[pos] != -1) return dp[pos];
ll ans = 0,up = lim ? nums[pos] : 9;
for(int i = 0;i <= up;i ++) {
if(i == 4) continue;
ans += dfs(pos - 1,lim && i == up);
}
if(!lim) dp[pos] = ans;
return ans;
}
ll calc(ll k)
{
cnt = 0;
while(k) {
nums[cnt ++] = k % 10;
k /= 10;
}
rep(i,0,cnt - 1) dp[i] = -1;
return dfs(cnt - 1,true);
}
void solve()
{
ll k;
cin >> k;
ll l = 1,r = 5e12;
while(l <= r) {
ll mid = (l + r) >> 1;
if(calc(mid) <= k) l = mid + 1;
else r = mid - 1;
}
cout << l << '\n';
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int T = 1;
cin >> T;
while(T --) solve();
return 0;
}
(1)题目大意
给你一个图,问这个图是否由一个长度为k的一些环构成,并且这些环除了顶点其他的点都不相交。
(2)解题思路
考虑这个图的构成,只能由度数为2或者4的点构成,暂且称度数为4的点为中心点,度数为2的点为边缘点。
1.若图不连通,则不可能构成
2.若图中点度数不为2或者4,则不可能构成
3.若图中没有k个中心点,则不可能构成
4.若sqrt(n) != k * k,则图不可能构成
5.若图没有k*(k+1)条边,则也不可能构成
6.考虑中心点之间连边,若中心点的度数不为2,则不可能构成
7.考虑所有环向中心点合并,若有环点不为k,则不可能构成
8.若合并后图不连通,则不可能构成
以上操作可以用并查集判断。
(3)代码实现
#include <iostream>
#include <map>
#include <set>
#include <vector>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <stack>
#include <algorithm>
#include <numeric>
#include <cmath>
#include <unordered_map>
#include <deque>
#include <bitset>
#define rep(i,z,n) for(int i = z;i <= n; i++)
#define per(i,n,z) for(int i = n;i >= z; i--)
#define pii pair<int,int>
#define fi first
#define se second
#define vi vector<int>
#define vl vector<ll>
#define pb push_back
#define sz(x) (int)x.size()
#define all(x) (x).begin(),(x).end()
using namespace std;
using ll = long long;
const int N = 2e5 + 10;
pii E[N];
int f[N],sz[N];
int find(int x)
{
return x == f[x] ? x : f[x] = find(f[x]);
}
void merge(int x,int y)
{
int fx = find(x),fy = find(y);
if(fx == fy) return;
f[fx] = fy;
sz[fy] += sz[fx];
}
void solve()
{
int n,m;
cin >> n >> m;
vector <int> d(n + 1,0);
iota(f,f + n + 1,0);
rep(i,1,n) sz[i] = 1;
rep(i,1,m) {
cin >> E[i].fi >> E[i].se;
d[E[i].fi] ++,d[E[i].se] ++;
merge(E[i].fi,E[i].se);
}
int k = sqrt(n);
if(k * k != n || k <= 2 || k * (k + 1) != m) {
cout << "NO" << endl;
return;
}
rep(i,1,n) {
if(d[i] != 2 && d[i] != 4) {
cout << "NO" << endl;
return;
}
if(find(i) != find(1)) {
cout << "NO" << endl;
return;
}
}
iota(f,f + n + 1,0);
rep(i,1,n) sz[i] = 1;
vector <int> dd(n + 1,0);
vector <int> center;
rep(i,1,n) {
if(d[i] == 4) {
center.pb(i);
}
}
if(sz(center) != k) {
cout << "NO" << endl;
return;
}
int nm = 0;
rep(i,1,m) {
if(d[E[i].fi] == 4 && d[E[i].se] == 4) {
merge(E[i].fi,E[i].se);
dd[E[i].fi] ++;
dd[E[i].se] ++;
nm ++;
}
}
if(nm != k) {
cout << "NO" << endl;
return;
}
rep(i,0,k - 1) {
if(find(center[i]) != find(center[0]) || dd[center[i]] != 2) {
cout << "NO" << endl;
return;
}
}
rep(i,1,n) sz[i] = 1;
iota(f,f + 1 + n,0);
rep(i,1,m) {
if(d[E[i].fi] != 4 || d[E[i].se] != 4) {
if(d[E[i].fi] == 4) merge(E[i].se,E[i].fi);
else if(d[E[i].se] == 4) merge(E[i].fi,E[i].se);
else merge(E[i].fi,E[i].se);
}
}
rep(i,1,n) {
if(sz[find(i)] != k) {
cout << "NO" << endl;
return;
}
}
cout << "YES" << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int T = 1;
cin >> T;
while(T --) solve();
return 0;
}
(1)题目大意
给你一个长度为n的序列和一个k,问你划分序列最大长度的方案数是多少,把方案数输出出来。
(2)解题思路
参考Codeforces Round 863 (Div. 3) A - G2 - 知乎 (zhihu.com)
第一题可以n^4暴力搞过去,考虑第二题,需要优化成n^2。
定义dp[i][j]表示已经拿了i个点,最后一个的颜色为j的方案数。
1.当i%k==1的时候表示当前这个点可以随便选什么颜色,若第i/k这个段可以转移,则可以进行转移,dp[i][j]+=ans[j/k],然后当前这个点就可以用于后面点的转移了。否则就当段内点来转移,则必须和前面一个状态选j进行转移,dp[i][j] += dp[i - 1][j];
2.当i%k==0的时候,我们第ans[i/k]这段的答案+dp[i - 1][j],然后标记当前这段可以进行转移即可。
(3)代码实现
#include <iostream>
#include <map>
#include <set>
#include <vector>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <stack>
#include <algorithm>
#include <cmath>
#include <unordered_map>
#include <deque>
#include <bitset>
#include <assert.h>
#define rep(i,z,n) for(int i = z;i <= n; i++)
#define per(i,n,z) for(int i = n;i >= z; i--)
#define PII pair<int,int>
#define fi first
#define se second
#define vi vector<int>
#define vl vector<ll>
#define pb push_back
#define sz(x) (int)x.size()
#define all(x) (x).begin(),(x).end()
using namespace std;
using ll = long long;
const int N = 5010;
using i64 = long long;
constexpr int P = 1000000007;
// assume -P <= x < 2P
int Vnorm(int x) {
if (x < 0) {
x += P;
}
if (x >= P) {
x -= P;
}
return x;
}
template<class T>
T power(T a, i64 b) {
T res = 1;
for (; b; b /= 2, a *= a) {
if (b % 2) {
res *= a;
}
}
return res;
}
struct Mint {
int x;
Mint(int x = 0) : x(Vnorm(x)) {}
Mint(i64 x) : x(Vnorm(x % P)) {}
int val() const {
return x;
}
Mint operator-() const {
return Mint(Vnorm(P - x));
}
Mint inv() const {
assert(x != 0);
return power(*this, P - 2);
}
Mint &operator*=(const Mint &rhs) {
x = i64(x) * rhs.x % P;
return *this;
}
Mint &operator+=(const Mint &rhs) {
x = Vnorm(x + rhs.x);
return *this;
}
Mint &operator-=(const Mint &rhs) {
x = Vnorm(x - rhs.x);
return *this;
}
Mint &operator/=(const Mint &rhs) {
return *this *= rhs.inv();
}
friend Mint operator*(const Mint &lhs, const Mint &rhs) {
Mint res = lhs;
res *= rhs;
return res;
}
friend Mint operator+(const Mint &lhs, const Mint &rhs) {
Mint res = lhs;
res += rhs;
return res;
}
friend Mint operator-(const Mint &lhs, const Mint &rhs) {
Mint res = lhs;
res -= rhs;
return res;
}
friend Mint operator/(const Mint &lhs, const Mint &rhs) {
Mint res = lhs;
res /= rhs;
return res;
}
friend std::istream &operator>>(std::istream &is, Mint &a) {
i64 v;
is >> v;
a = Mint(v);
return is;
}
friend std::ostream &operator<<(std::ostream &os, const Mint &a) {
return os << a.val();
}
};
int c[N],cnt;
int n,k;
void solve()
{
cin >> n >> k;
vector<vector<Mint>> dp(n + 1,vector<Mint>(n + 1,0));
vector<Mint> ans(n + 1,0);
vector<bool> can(n + 1,0);
vector<vector<bool>> vis(n + 1,vector<bool>(n + 1,0));
vis[0][0] = true;
dp[0][0] = 1;
can[0] = true;
rep(i,1,n) cin >> c[i];
ans[0] = 1;
rep(i,1,n) {
per(j,i,1) {
if(j % k == 1) {
if(can[j / k]) {
vis[j][c[i]] = true;
dp[j][c[i]] += ans[j / k];
}
}
else {
if(vis[j - 1][c[i]]) {
vis[j][c[i]] = true;
dp[j][c[i]] += dp[j - 1][c[i]];
}
}
if(j % k == 0 && vis[j][c[i]]) {
ans[j / k] += dp[j - 1][c[i]];
can[j / k] = true;
}
}
}
per(i,n,0) {
if(can[i]) {
cout << ans[i] << '\n';
return;
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int T = 1;
cin >> T;
while(T --) solve();
return 0;
}