文章目录
前言
1104AB,1103A是水题
1103B是不错的交互题
C小清新构造
D毒瘤优化状压
E是恶心数学题(直接弃疗)
CF1104A Splitting into digits
Description \text{Description} Description
给定一个数字 n n n ,请将它拆分成 a 1 + a 2 + ⋯ + a m , a i ∈ [ 1 , 9 ] a_1+a_2+\cdots + a_m,a_i \in [1,9] a1+a2+⋯+am,ai∈[1,9],使得 ∑ i = 1 m a i = n \sum_{i=1}^ma_i = n ∑i=1mai=n,并且使 a i a_i ai 中不同的数尽量少。
输出方案,两行,第一行为数的个数 m m m,第二行为 m m m个数,由空格隔开,分别为 a 1 − a m a_1 - a_m a1−am。
Solution \text{Solution} Solution
智障题。输出 n n n 个 1 1 1 即可…
Description \text{Description} Description
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e6+100;
inline ll read(){
ll x(0),f(1);char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
int n;
int main(){
n=read();
for(int i=1;i<=9;i++){
if(n%i==0){
printf("%d\n",n/i);
while(n) printf("%d ",i),n-=i;
return 0;
}
}
printf("%d\n",(n+8)/9);
while(n>9) printf("9 ");n-=9;
printf("%d",n);
}
CF1104B Game with string
Description \text{Description} Description
A \text{A} A 与 B \text{B} B 正在玩一个关于由小写拉丁字符构成的字符串 s s s 的游戏。
每一个人会轮流操作,先 A \text{A} A 后 B \text{B} B。
对于每一次操作,操作者需要将 s s s 中的两个 连续且相同 的字符消除,消除后的字符串由另一个人操作。
对于每一次操作,如果不能找到两个符合要求的字符,那么操作者输。
Solution \text{Solution} Solution
水题。
显然博弈论只是层皮,胜负就与操作次数的奇偶性有关。
由于有删除操作,我写了个链表,每次删除后再递归往两侧看能不能接着删。
看其他题解许多使用了栈,做法也很简单。
Code \text{Code} Code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e5+100;
inline ll read(){
ll x(0),f(1);char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
int n;
int l[N],r[N],ans;
char s[N];
bool vis[N];
void del(int x,int y){
++ans;vis[x]=vis[y]=1;
int xx=l[x],yy=r[y];
r[xx]=yy;l[yy]=xx;
if(xx>0&&yy<=n&&s[xx]==s[yy]) del(xx,yy);
return;
}
int main(){
scanf(" %s",s+1);n=strlen(s+1);
for(int i=1;i<=n;i++) l[i]=i-1,r[i]=i+1;
r[0]=1;l[n+1]=n;
for(int i=1;i<=n;i++){
if(vis[i]) continue;
if(s[i]==s[l[i]]) del(l[i],i);
}
if(ans&1) printf("Yes");
else printf("No");
}
CF1103A Grid game
Description \text{Description} Description
你有一个 4 × 4 4\times4 4×4 的棋盘和一些 1 × 2 1\times2 1×2 大小的方格,给你放入的顺序, 0 0 0 表示竖着放, 1 1 1 表示横着放,每当一行或一列全放满时会将这一行或列上的消除,输出任意一种使小方格不重叠的方案。
Solution \text{Solution} Solution
似乎和其他题解的方法不太一样。
竖着的先放
(
1
,
1
)
(1,1)
(1,1),再放
(
3
,
1
)
(3,1)
(3,1) 把上一个消掉。
横着的先放
(
4
,
3
)
(4,3)
(4,3),再放
(
4
,
1
)
(4,1)
(4,1) 把上一个消掉。
永远不会有冲突。
Code \text{Code} Code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e5+100;
inline ll read(){
ll x(0),f(1);char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
int n;
int a,b;
char s[N];
int main(){
scanf(" %s",s+1);n=strlen(s+1);
for(int i=1;i<=n;i++){
if(s[i]=='0'){
if(a) printf("3 1\n");
else printf("1 1\n");
a^=1;
}
else{
if(b) printf("4 1\n");
else printf("4 3\n");
b^=1;
}
}
}
CF1103B Game with modulo
Description \text{Description} Description
未知一个数
a
a
a,让你每次猜两个数
x
x
x 和
y
y
y,若
(
x
m
o
d
a
)
≥
(
y
m
o
d
a
)
(x\bmod a)\ge (y\bmod a)
(xmoda)≥(ymoda) 返回 x
,否则返回 y
。让你猜测次数少于
60
60
60 次的时候猜出数
a
a
a。
a
≤
2
×
1
0
9
a\le 2\times 10^9
a≤2×109
Solution \text{Solution} Solution
一开始,令
x
=
1
x=1
x=1。
不断进行一下过程:
- 询问 x x x 与 2 x 2x 2x。
- 若 x m o d a < 2 x m o d a x\bmod a< 2x\bmod a xmoda<2xmoda,说明 a > 2 x a>2x a>2x,令 x ← 2 x x\gets 2x x←2x,回到第一步。
- 若 x m o d a > 2 x m o d a x\bmod a> 2x\bmod a xmoda>2xmoda,说明 a ≤ 2 x a\le 2x a≤2x,也就是 a ∈ ( x , 2 x ] a\in (x,2x] a∈(x,2x],进入第四步。
- 现在已知 a ∈ ( x , 2 x ] a\in (x,2x] a∈(x,2x],二分找到 a a a 的值即可。
a = 1 a=1 a=1 的情况比较恶心,建议特判处理。
Code \text{Code} Code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=4e5+100;
inline ll read(){
ll x(0),f(1);char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
int n,m;
char c;
inline char ask(int x,int y){
printf("? %d %d\n",x,y);fflush(stdout);
scanf(" %c",&c);
return c;
}
char s[105];
signed main(){
#ifndef ONLINE_JUDGE
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
#endif
while(1){
scanf(" %s",s+1);
if(s[1]=='m'||s[1]=='e') return 0;
int x=1;
while(1){
if(ask(x,x<<1)=='x') break;
else x<<=1;
}
if(x==1){
if(ask(2,1)=='y') printf("! 2\n");
else printf("! 1\n");
fflush(stdout);
}
else{
int st=x+1,ed=x<<1;
while(st<ed){
int mid=(st+ed)>>1;
if(ask(mid,x)=='x') st=mid+1;
else ed=mid;
}
printf("! %d\n",st);fflush(stdout);
}
}
return 0;
}
/*
*/
CF1103C Johnny Solving
Description \text{Description} Description
给出一张无重边的无向图(保证每个点度数大于等于 3 3 3)和一个限制 k k k,需要你构造以下两种情况中的一种:
1、找出一条路径长度为 n / k n/k n/k。
2、找出 k k k 个环,使得每个环的长度大于 3 3 3 而且不是 3 3 3 的倍数,并且要求保证每个环中至少有一个点在这 k k k 个环里只出现一次。
Solution \text{Solution} Solution
不错的一道题。
不难想到先建出 dfs 生成树的套路。
然后,若直径大于
n
/
k
n/k
n/k,就已经满足条件一了。
否则,必然有每个结点的深度不超过
n
/
k
n/k
n/k,那么叶子的数量必然不少于
k
k
k 个。
同时,每个叶子
u
u
u 必然至少有两条非树返祖边。,假设分别连向
x
,
y
x,y
x,y。
分类讨论一下一定有一个不是
3
3
3 的倍数的环。
把叶子作为代表结点即可。
Code \text{Code} Code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=5e5+100;
inline ll read(){
ll x(0),f(1);char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
int n,m,k;
struct node{
int to,nxt;
}p[N<<1];
int fi[N],cnt;
inline void addline(int x,int y){
p[++cnt]=(node){y,fi[x]};fi[x]=cnt;
return;
}
bool vis[N],jd[N];
vector<int>v[N];
int fa[N],dep[N];
void dfs(int x,int f){
fa[x]=f;dep[x]=dep[f]+1;vis[x]=1;
for(int i=fi[x];~i;i=p[i].nxt){
int to=p[i].to;
if(to==f) continue;
if(vis[to]){
if(dep[to]<dep[x]) v[x].push_back(to);
}
else{
jd[x]=1;dfs(to,x);
}
}
return;
}
void print(int x,int tp){
//printf("%d\n",dep[x]-dep[tp]+1);
while(x!=fa[tp]) printf("%d ",x),x=fa[x];
putchar('\n');
return;
}
inline bool ok(int o){return o>2&&o%3;}
bool bac[4];
bool pd[N];
signed main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
#endif
memset(fi,-1,sizeof(fi));cnt=-1;
n=read();m=read();k=read();
for(int i=1;i<=m;i++){
int x=read(),y=read();
addline(x,y);addline(y,x);
}
dfs(1,0);
for(int i=1;i<=n;i++){
if(1ll*dep[i]*k>=n){
printf("PATH\n");
printf("%d\n",dep[i]);
print(i,1);return 0;
}
}
printf("CYCLES\n");
for(int i=1;i<=n&&k;i++){
int x(0),y(0),z(0);bac[0]=bac[1]=bac[2]=0;
if(jd[i]) continue;
for(auto now:v[i]){
if(pd[now]) continue;
if(ok(dep[i]-dep[now]+1)){
printf("%d\n",dep[i]-dep[now]+1);
pd[i]=1;
print(i,now);k--;break;
}
else if(x&&ok(abs(dep[x]-dep[now])+1+1)){
if(dep[x]>dep[now]) swap(x,now);
printf("%d\n%d ",dep[now]-dep[x]+1+1,i);
print(now,x);
pd[i]=1;k--;
break;
}
else if(y&&ok(abs(dep[y]-dep[now])+1+1)){
if(dep[y]>dep[now]) swap(y,now);
printf("%d\n%d ",dep[now]-dep[y]+1+1,i);
print(now,y);
pd[i]=1;k--;
break;
}
else if(z&&ok(abs(dep[z]-dep[now])+1+1)){
if(dep[z]>dep[now]) swap(z,now);
printf("%d\n%d ",dep[now]-dep[z]+1+1,i);
print(now,z);
pd[i]=1;k--;
break;
}
if(!bac[dep[now]%3]){
bac[dep[now]%3]=1;
if(!x) x=now;
else if(!y) y=now;
else if(!z) z=now;
}
}
}
return 0;
}
/*
*/
CF1103D Professional layer
Description \text{Description} Description
给定 1 ≤ n ≤ 1 0 6 1 \le n \le 10^6 1≤n≤106 个正整数 a i , 1 ≤ a i ≤ 1 0 12 a_i,1 \le a_i≤10^{12} ai,1≤ai≤1012,以及正整数 1 ≤ k ≤ 1 0 12 1 \le k \le 10^{12} 1≤k≤1012,修改第 i i i 个正整数 a i a_i ai 的花费为 e i , 1 ≤ e i ≤ 1 0 9 e_i,1 \le e_i \le 10^9 ei,1≤ei≤109 。
要求选出若干个正整数进行一次修改,使得修改后所有正整数的最大公约数等于 1 1 1 。修改操作为:对于正整数 a a a,选择 a a a 的一个约数 d ≤ k d \le k d≤k,把 a a a 修改为 $ \frac{a}{d}$。
设选出并修改的正整数有 x x x 个,他们的花费之和为 y y y,则总的修改花费为 x × y x \times y x×y。求最小花费。
Solution \text{Solution} Solution
毒瘤状压题。
不难想到,公因数的质因子不超过
11
11
11 个,可以状压。
关键就是对复杂度的优化。
(以下设质因子个数为
k
k
k)
朴素 dp 的复杂度是
O
(
n
k
3
k
)
O(nk3^k)
O(nk3k),难以通过。
考虑优化。
首先,注意到会有大量的重复数(打表可知不同的数只有
1
0
4
10^4
104 个),每种数字取代价最小的前
k
k
k 个即可。
然后,数的数里降到了十万级别,我们可以暴力求出每个数可以转移到那些质因数集合,而每个集合其实也只需要取前
k
k
k 个数进行转移,所以转移数降到了
k
×
2
k
k\times2^k
k×2k。
对每个转移集合的补集枚举子集转移,再加上枚举一维选取个数的复杂度,总复杂度
3
k
×
k
2
3^k\times k^2
3k×k2。
注意每次不能暴力更新滚动数组,复杂度会假掉,所以需要开个 vector 记录一下更新了哪些状态。
注意开 longlong。
Code \text{Code} Code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=2e6+100;
inline ll read(){
ll x(0),f(1);char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
int n,m;
ll k,flag;
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
struct node{
ll a,c;
}p0[N],p[N];
bool cmpc(node x,node y){return x.c<y.c;}
bool cmpa(node x,node y){return x.a<y.a;}
ll tot,g;
ll dp[2][13][2105],now,nxt;
ll prime[13],cnt;
map<ll,int>mp;
vector<int>v[2105];
ll w[13],mi[13],bit[2105];
vector<int>vv[N];
void findtrans(int id){
ll x=p[id].a;
//ll x=p[i].a;
for(int j=1;j<=cnt;j++){
w[j]=1;
while(x%prime[j]==0){
x/=prime[j];w[j]*=prime[j];
}
}
for(int s=0;s<(1<<cnt);s++){
ll o=1;int ss=s;
if((int)v[s].size()==cnt) continue;
while(ss){
o*=w[bit[ss&-ss]+1];ss-=ss&-ss;
}
if(o<=k){
//v.push_back(s);
v[s].push_back(id);
//printf(" s=%d o=%lld\n",s,o);
}
}
}
void init(){
int tp=floor(sqrt(g));
for(int i=2;i<=tp;i++){
if(g%i==0){
prime[++cnt]=i;
while(g%i==0) g/=i;
}
}
if(g>1) prime[++cnt]=g;
sort(p0+1,p0+1+n,cmpc);
for(int i=1;i<=n;i++){
int x=p0[i].a;
if(mp.find(x)!=mp.end()&&mp[x]>=cnt) continue;
p[++tot]=p0[i];mp[x]=mp[x]+1;
/*for(int j=1;j<=cnt;j++){
if(x%prime[j]==0){
p[++tot]=p0[i];mp[x]=mp[x]+1;break;
}
}*/
}
mi[0]=1;bit[1]=0;
for(int i=1;i<=cnt;i++) mi[i]=mi[i-1]<<1,bit[mi[i]]=i;
for(int i=1;i<=tot;i++) findtrans(i);
//sort(p+1,p+1+tot,cmpa);
for(int i=0;i<(1<<cnt);i++){
for(auto x:v[i]) vv[x].push_back(i);
}
}
vector<int>tr;
void DP(){
memset(dp,0x3f,sizeof(dp));dp[now=1][0][0]=0;
for(int i=1;i<=tot;i++){
//swap(nxt,now);
tr.clear();
for(auto ns:vv[i]){
int t=((1<<cnt)-1)^ns,T=t;
//debug("ns=%d\n",ns);
dp[nxt][1][ns]=min(dp[nxt][1][ns],p[i].c);
tr.push_back(ns);
for(;t;t=T&(t-1)){
tr.push_back(t|ns);
for(int o=0;o<cnt;o++){
//debug("ns=%d t=%d o=%d\n",ns,t,o);
dp[nxt][o+1][t|ns]=min(dp[nxt][o+1][t|ns],dp[now][o][t]+p[i].c);
}
}
}
for(auto s:tr){
for(int o=0;o<=cnt;o++) dp[now][o][s]=min(dp[now][o][s],dp[nxt][o][s]);
}
/*
for(int s=0;s<(1<<cnt);s++){
for(int o=0;o<=cnt;o++){
dp[nxt][o][s]=min(dp[nxt][o][s],dp[now][o][s]);
//if(dp[nxt][o][s]<1e9) printf("s=%d num=%d dp=%lld\n",s,o,dp[nxt][o][s]);
}
}*/
}
}
void findans(){
ll ans(2e18),op;
for(int i=0;i<=cnt;i++){
if(dp[now][i][(1<<cnt)-1]<1e18){
if(ans>dp[now][i][(1<<cnt)-1]*i) op=i;
ans=min(ans,dp[now][i][(1<<cnt)-1]*i);
}
}
printf("%lld\n",ans>1e18?-1:ans);
//if(flag) printf("g=%lld op=%lld tot=%lld\n",g,op,tot);
//debug("ans=%lld num=%lld\n",ans,op);
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
#endif
n=read();k=read();
for(int i=1;i<=n;i++) p0[i].a=read(),g=gcd(g,p0[i].a);
for(int i=1;i<=n;i++) p0[i].c=read();
//printf("g=%lld\n",g);
flag=p0[1].a==204367626045ll;
init();//debug("ok\n");
DP();
findans();
return 0;
}
/*
*/