文章目录
- 前言
- CF1104A Splitting into digits
- CF1104B Game with string
- CF1103A Grid game
- CF1103B Game with modulo
- CF1103C Johnny Solving
- CF1103D Professional layer
前言
1104AB,1103A是水题
1103B是不错的交互题
C小清新构造
D毒瘤优化状压
E是恶心数学题(直接弃疗)
CF1104A Splitting into digits
Description\text{Description}Description
给定一个数字 nnn ,请将它拆分成 a1+a2+⋯+am,ai∈[1,9]a_1+a_2+\cdots + a_m,a_i \in [1,9]a1+a2+⋯+am,ai∈[1,9],使得 ∑i=1mai=n\sum_{i=1}^ma_i = n∑i=1mai=n,并且使 aia_iai 中不同的数尽量少。
输出方案,两行,第一行为数的个数 mmm,第二行为mmm个数,由空格隔开,分别为 a1−ama_1 - a_ma1−am。
Solution\text{Solution}Solution
智障题。输出 nnn 个 111 即可…
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 正在玩一个关于由小写拉丁字符构成的字符串 sss 的游戏。
每一个人会轮流操作,先 A\text{A}A 后 B\text{B}B。
对于每一次操作,操作者需要将 sss 中的两个 连续且相同 的字符消除,消除后的字符串由另一个人操作。
对于每一次操作,如果不能找到两个符合要求的字符,那么操作者输。
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×44\times44×4 的棋盘和一些 1×21\times21×2 大小的方格,给你放入的顺序,000 表示竖着放,111 表示横着放,每当一行或一列全放满时会将这一行或列上的消除,输出任意一种使小方格不重叠的方案。
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
未知一个数 aaa,让你每次猜两个数 xxx 和 yyy,若 (xmoda)≥(ymoda)(x\bmod a)\ge (y\bmod a)(xmoda)≥(ymoda) 返回 x
,否则返回 y
。让你猜测次数少于 606060 次的时候猜出数 aaa。
a≤2×109a\le 2\times 10^9a≤2×109
Solution\text{Solution}Solution
一开始,令 x=1x=1x=1。
不断进行一下过程:
- 询问 xxx 与 2x2x2x。
- 若 xmoda<2xmodax\bmod a< 2x\bmod axmoda<2xmoda,说明 a>2xa>2xa>2x,令 x←2xx\gets 2xx←2x,回到第一步。
- 若 xmoda>2xmodax\bmod a> 2x\bmod axmoda>2xmoda,说明 a≤2xa\le 2xa≤2x,也就是 a∈(x,2x]a\in (x,2x]a∈(x,2x],进入第四步。
- 现在已知 a∈(x,2x]a\in (x,2x]a∈(x,2x],二分找到 aaa 的值即可。
a=1a=1a=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
给出一张无重边的无向图(保证每个点度数大于等于 333)和一个限制 kkk,需要你构造以下两种情况中的一种:
1、找出一条路径长度为 n/kn/kn/k。
2、找出 kkk 个环,使得每个环的长度大于 333 而且不是 333 的倍数,并且要求保证每个环中至少有一个点在这 kkk 个环里只出现一次。
Solution\text{Solution}Solution
不错的一道题。
不难想到先建出 dfs 生成树的套路。
然后,若直径大于 n/kn/kn/k,就已经满足条件一了。
否则,必然有每个结点的深度不超过 n/kn/kn/k,那么叶子的数量必然不少于 kkk 个。
同时,每个叶子 uuu 必然至少有两条非树返祖边。,假设分别连向 x,yx,yx,y。
分类讨论一下一定有一个不是 333 的倍数的环。
把叶子作为代表结点即可。
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_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);
#endifmemset(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≤1061 \le n \le 10^61≤n≤106 个正整数 ai,1≤ai≤1012a_i,1 \le a_i≤10^{12}ai,1≤ai≤1012,以及正整数 1≤k≤10121 \le k \le 10^{12}1≤k≤1012,修改第 iii 个正整数 aia_iai 的花费为 ei,1≤ei≤109e_i,1 \le e_i \le 10^9ei,1≤ei≤109 。
要求选出若干个正整数进行一次修改,使得修改后所有正整数的最大公约数等于 111 。修改操作为:对于正整数 aaa,选择 aaa 的一个约数 d≤kd \le kd≤k,把 aaa 修改为 $ \frac{a}{d}$。
设选出并修改的正整数有 xxx 个,他们的花费之和为 yyy,则总的修改花费为 x×yx \times yx×y。求最小花费。
Solution\text{Solution}Solution
毒瘤状压题。
不难想到,公因数的质因子不超过 111111 个,可以状压。
关键就是对复杂度的优化。
(以下设质因子个数为 kkk)
朴素 dp 的复杂度是 O(nk3k)O(nk3^k)O(nk3k),难以通过。
考虑优化。
首先,注意到会有大量的重复数(打表可知不同的数只有 10410^4104 个),每种数字取代价最小的前 kkk 个即可。
然后,数的数里降到了十万级别,我们可以暴力求出每个数可以转移到那些质因数集合,而每个集合其实也只需要取前 kkk 个数进行转移,所以转移数降到了 k×2kk\times2^kk×2k。
对每个转移集合的补集枚举子集转移,再加上枚举一维选取个数的复杂度,总复杂度 3k×k23^k\times k^23k×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_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);
#endifn=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;
}
/**/