CF1228——记一次和紫名失之交臂的CF
CF1228——记一次和紫名失之交臂的CF
第无数次和暴涨失之交臂
A
题目大意给定\(l,r\)输出任意一个\(l,r\)之间的每一位都不同的数
\((l <= r <= 10^5)\)
O(nlogn)暴力判断即可
其实也可以暴力枚举所有全排列
我这里选择了较为简单的暴力写法
#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
#include<cctype>
#include<vector>
#include<ctime>
#define LL long long
#define pii pair<int,int>
#define mk make_pair
#define fi first
#define se second
using namespace std;
inline int read(){
int v = 0,c = 1;char ch = getchar();
while(!isdigit(ch)){
if(ch == '-') c = -1;
ch = getchar();
}
while(isdigit(ch)){
v = v * 10 + ch - 48;
ch = getchar();
}
return v * c;
}
bool book[13];
inline bool check(int x){
memset(book,0,sizeof(book));
while(x){
if(book[x % 10]) return 0;
book[x % 10] = 1;
x /= 10;
}
return 1;
}
int main(){
int l = read(),r = read();
for(int i = l;i <= r;++i){
if(check(i)) return printf("%d\n",i) * 0;
}
puts("-1");
return 0;
}
B
题目不太好复述
我们想每一个限制实质上是强制确定了前\(x\)个位置的颜色
如果没出现冲突
设有\(res\)个位置没有被确定
那么这些位置是可黑可白的
答案就是\(2^{res}\),出现冲突就是\(0\)
#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
#include<cctype>
#include<vector>
#include<ctime>
#define LL long long
#define pii pair<int,int>
#define mk make_pair
#define fi first
#define se second
using namespace std;
const int N = 2e6 + 3;
const LL mod = 1e9 + 7;
inline int read(){
int v = 0,c = 1;char ch = getchar();
while(!isdigit(ch)){
if(ch == '-') c = -1;
ch = getchar();
}
while(isdigit(ch)){
v = v * 10 + ch - 48;
ch = getchar();
}
return v * c;
}
LL p[N];
int r[N],c[N];
int n,m;
int ans[2005][2005];
int main(){
bool flag = 0;
memset(ans,-1,sizeof(ans));
p[0] = 1;
for(int i = 1;i <= 1500000;++i) p[i] = p[i - 1] * 2 % mod;
n = read(),m = read();
for(int i = 1;i <= n;++i){
int x = read();
for(int j = 1;j <= x;++j){
if(ans[i][j] == 0) flag = 1;
ans[i][j] = 1;
}
x++;
if(ans[i][x] == 1) flag = 1;
ans[i][x] = 0;
}
for(int i = 1;i <= m;++i){
int x = read();
for(int j = 1;j <= x;++j){
if(ans[j][i] == 0) flag = 1;
ans[j][i] = 1;
}
x++;
if(ans[x][i] == 1) flag = 1;
ans[x][i] = 0;
}
if(flag){
printf("0\n");
return 0;
}
int tot = 0;
for(int i = 1;i <= n;++i){
for(int j = 1;j <= m;++j)
tot += (ans[i][j] == -1);
}
printf("%lld\n",p[tot]);
return 0;
}
C
题目定义了1长串的式子
就是为了告诉你给定\(m,x\)
求\(1-m\)中所有\(p\),\(p^2\),\(\dots\),\(p^{\infty}\)\((p|x,p\in prime)\)的乘积
这个
我们考虑先算\(p^1\)的贡献,再算\(p^2\)的贡献
我们只需要对\(x\)质因数分解,然后对于每个质因子求一下上面的式子的贡献
时间复杂度\(\sqrt{x}log(n)\)
#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
#include<cctype>
#include<vector>
#include<ctime>
#define LL unsigned long long
#define pii pair<int,int>
#define mk make_pair
#define fi first
#define se second
using namespace std;
const LL mod = 1e9 + 7;
int tot = 0;
LL p[1000005];
inline LL read(){
LL v = 0,c = 1;char ch = getchar();
while(!isdigit(ch)){
if(ch == '-') c = -1;
ch = getchar();
}
while(isdigit(ch)){
v = v * 10 + ch - 48;
ch = getchar();
}
return v * c;
}
inline void work(LL x){
LL rr = x;
for(int i = 2;1ll * i * i <= x;++i){
if(rr % i == 0){
p[++tot] = i;
while(rr % i == 0) rr /= i;
}
if(rr == 1) break;
}
if(rr != 1) p[++tot] = rr;
}
LL n,m;
inline LL quick(LL x,LL y){
LL res = 1;
while(y){
if(y & 1) res = res * x % mod;
x = x * x % mod;
y >>= 1;
}
return res;
}
int main(){
n = read(),m = read();
work(n);
LL ans = 1;
for(int i = 1;i <= tot;++i){
LL res = p[i];
LL rest = m;
while(rest != 0){
ans = ans * quick(p[i],(rest / res)) % mod;
rest /= res;
}
}
printf("%lld\n",ans);
return 0;
}
D
题目大意
给定一个\(n\)个点,\(m\)条边的图,把\(n\)个点分成三个集合,使得两两集合为完全二分图
一种情况每判就GG了
首先我们发现一个点和他没有边的点必须在同一集合
而且我们最多找三次没有所属集合的点(因为题目要求就是选择三个集合)
那么我们枚举一个点
之后强制和他没有直接相连的点和他在同一集合如果这个点已经在别的集合,很明显无解
最后我们一定会得到三个集合
但是我们没法保证正确性
我们再尝试一一判断所有情况
\(1\)任一点都必须且只能属于一个集合
\(2\)同一集合内部不能有边
\(3\)两两集合是完全二分图
只有满足上述条件才是一组合法解
\(2\)我们可以通过枚举每一条边来实现
\(3\)我们可以通过记录一下每个点的度数,看看他是否等于另外两个集合的大小即可
#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
#include<cctype>
#include<vector>
#include<ctime>
#include<set>
#define LL long long
#define pii pair<int,int>
#define mk make_pair
#define fi first
#define se second
using namespace std;
const int N = 1e6 + 3;
vector<int>G[N];
vector<int>gg[5];
int n,m,size,sz1,sz2,sz3;
int ans[N],d[N];
int cc[N];
set <int> s[N];
int vis[N];
bool flag = 1;
inline int read(){
int v = 0,c = 1;char ch = getchar();
while(!isdigit(ch)){
if(ch == '-') c = -1;
ch = getchar();
}
while(isdigit(ch)){
v = v * 10 + ch - 48;
ch = getchar();
}
return v * c;
}
inline void dfs(int x){
size++;
vis[x] = 1;
for(int i = 0;i < (int)G[x].size();++i){
int y = G[x][i];
if(vis[y]) continue;
dfs(y);
}
}
int main(){
n = read(),m = read();
for(int i = 1;i <= m;++i){
int x = read(),y = read();
G[x].push_back(y);
G[y].push_back(x);
d[x]++,d[y]++;
}
memset(vis,0,sizeof(vis));
for(int i = 0;i < (int)G[1].size();++i){
int y = G[1][i];
vis[y] = 1;
}
for(int i = 1;i <= n;++i) if(!vis[i]) ans[i] = 1,sz1++;
int now = 2;
while(now <= n && ans[now] == 1)now++;
if(now > n){
printf("-1\n");
return 0;
}
memset(vis,0,sizeof(vis));
for(int i = 0;i < (int)G[now].size();++i){
int y = G[now][i];
if(ans[y] == 2) flag = 0;
vis[y] = 1;
}
for(int i = 1;i <= n;++i){
if(!vis[i]){
if(ans[i] == 1) flag = 0;
ans[i] = 2;
sz2++;
}
}
now++;
while(now <= n && (ans[now] == 1 || ans[now] == 2))now++;
if(now > n){
printf("-1\n");
return 0;
}
memset(vis,0,sizeof(vis));
for(int i = 0;i < (int)G[now].size();++i){
int y = G[now][i];
if(ans[y] == 3) flag = 0;
vis[y] = 1;
}
for(int i = 1;i <= n;++i){
if(!vis[i]){
if(ans[i] == 1 || ans[i] == 2) flag = 0;
else ans[i] = 3;
sz3++;
}
}//for(int i = 1;i <= n;++i) printf("%d ",ans[i]);puts("");
now++;
while(now <= n && (ans[now] == 1 || ans[now] == 2 || ans[now] == 3))now++;
if(now <= n) flag = 0;
for(int i = 1;i <= n;++i){
for(int j = 0;j < (int)G[i].size();++j){
int y = G[i][j];
if(ans[i] == ans[y]) flag = 0;
}
if(ans[i] == 1 && d[i] != sz2 + sz3) flag = 0;
if(ans[i] == 2 && d[i] != sz1 + sz3) flag = 0;
if(ans[i] == 3 && d[i] != sz1 + sz2) flag = 0;
}
if(flag == 0) printf("-1");
else for(int i = 1;i <= n;++i) printf("%d ",ans[i]);
return 0;
}
E
艹,没读E题,结果是个ZZ题
题目大意;给定一个\(n\times n\)的矩阵,每个位置可以填\(1-k\),问有多少种填法使得每一行每一列最小值都是\(1\)
\(n\le 250,k\le10^9\)
首先,考虑容斥,我们强制某些行某些列不能为1,其他随便填
容斥式子
就是强制的位置不能出现\(1\)其他位置随便选
唯一不懂的地方是\((-1)^{i + j}\)
\(update\)
因为行和列在容斥中式独立的
所以\((-1)^{i + j }\)本质是\((-1 )^i \times (-1) ^ j\)
所以多维容斥本质也是每一维度互相独立然后总和算贡献
#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
#include<cctype>
#include<vector>
#include<ctime>
#define LL long long
#define pii pair<int,int>
#define mk make_pair
#define fi first
#define se second
using namespace std;
const int N = 505;
const LL mod = 1e9 + 7;
LL C[N][N];
inline int read(){
int v = 0,c = 1;char ch = getchar();
while(!isdigit(ch)){
if(ch == '-') c = -1;
ch = getchar();
}
while(isdigit(ch)){
v = v * 10 + ch - 48;
ch = getchar();
}
return v * c;
}
inline LL quick(LL x,LL y){
LL res = 1;
while(y){
if(y & 1) res = res * x % mod;
x = x * x % mod;
y >>= 1;
}
return res;
}
int n,k;
int main(){
C[0][0] = 1;
for(int i = 1;i <= 500;++i){
C[i][0] = 1;
for(int j = 1;j <= i;++j)
C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % mod;
}
n = read(),k = read();
LL ans = 0;
for(int i = 0;i <= n;++i){
for(int j = 0;j <= n;++j){
LL res = C[n][i] * C[n][j] % mod * quick(k - 1,(i + j) * n - i * j) % mod
* quick(k,n * n - ((i + j) * n - i * j)) % mod;
// printf("%d %d %lld\n",i,j,res);
if((i + j) & 1) ans = ans - res;
else ans = ans + res;
if(ans >= mod) ans -= mod;
if(ans < 0) ans += mod;
}
}
printf("%lld\n",ans);
return 0;
}