早起登cf的网速真是太舒适了~
结合最近参加的正式赛事来看,突然发现熬夜cf的唯二两个帮助(目前发现的),除了可以被迫地遇到一些见过或没见过的知识点然后积累起来,第二点就是可以帮助自己在面临一些确实应该去做的事情的时候不会再迟疑. 比 较 抽 象 ~.
edu #63
A. Reverse a Substring
签到签的有点迟了,一个是日常打不开题,一个是bug不好找,刚刚回去看了好一会儿,想起来是自己某处修改早了.
B. Game with Telephone Numbers
是一个披着博弈外衣的简单贪心题.
C. Alarm Clocks Everywhere
对就是这道题,没开llwa了五次.可我却不断地在查算法.
D. Beautiful Array
看了眼tutorial自己最最开始的做法是错的,幸好没有那样写。考虑答案=max(sum[r]*x+sum[l]*x+pre[l-1]+suf[r+1]),然后做法就超级自然了;当然std的dp更具有一般性,大概在最大字段和的基础上增加两个状态,分别表示当前字段和有没有断,被x乘过的区间有没有断. 不过还没有细想为什么最初的做法是错误的.
E题是个取模意义下的高斯消元,什么都来不及做就直接开始写了.做过的第二个交互题,比第一个舒适多了!!!
#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
#define N 5020
#define mo 1000003
using namespace std;
int cas,n,m;
ll a[N][N],del;
ll quickmi(ll x,ll b){
ll t=1;
while(b>0){
if(b%2){
t=t*x%mo;
}x=x*x%mo;
b/=2;
}return t;
}
bool gauss(){
int n=11;
for(int i=1;i<=n;i++){
int k=i;
for(int j=i+1;j<=n;j++)if(abs(a[j][i])>abs(a[k][i]))k=j;
del=a[k][i];
ll qdel=quickmi(del,mo-2);
if(a[k][i]==0)return 0;
//printf("%d\n",i);
for(int j=i;j<=n+1;j++)swap(a[i][j],a[k][j]);
for(int j=i;j<=n+1;j++)a[i][j]=(a[i][j]*qdel)%mo;
for(k=1;k<=n;k++)if(k!=i){
del=a[k][i];
for(int j=i;j<=n+1;j++)a[k][j]=(a[k][j]-a[i][j]*del%mo+mo)%mo;
}
}
return 1;
}
int main(){
for(int i=0;i<=10;i++){
printf("? %d\n",i);
fflush(stdout);
scanf("%lld",&a[i+1][12]);
a[i+1][1]=1;
for(int j=2;j<=11;j++){
a[i+1][j]=(a[i+1][j-1]*i)%mo;
}
}
if(gauss()==0){
printf("! -1\n");
fflush(stdout);
}else{
for(int i=0;i<=mo;i++){
ll t=1,s=0;
for(int j=1;j<=11;j++){
s=(s+t*a[j][12])%mo;
t=t*i%mo;
}
if(s==0){
printf("! %d\n",i);
fflush(stdout);
return 0;
}
}
printf("! -1\n");
fflush(stdout);
}
}
F. Delivery Oligopoly
晚上冷静一下把它补掉;
Codeforces Round #554 (Div. 2)
某天fby看到我的屏幕上显示了这套题的Neko系列脱口而出:Neko不是日语里的猫嘛^_^ 2333太可爱了..虽然百度了一下还得到了另一个科学名词的意思...
A. Neko Finds Grapes
是个奇偶判一判的水题.
B. Neko Performs Cat Furrier Transform
长得一脸数学的样子,暗暗叹了口气,heltion应该做的很愉快吧.
感觉自己在乱搞,不过好在这是一次成功的乱搞.
#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
#define N 2002020
using namespace std;
int cas,n,m;
int tot,a[N];
ll bit[N],x;
int find(ll x){
int k=-1,i;
if(x==0)return -2;
for(i=40;i>=0;i--)if(x&bit[i])break;
for(i=i-1;i>=0;i--){
if((x&bit[i])==0){
if((x&(bit[i+1]-1))==0){
if(i==0)return -2;
return i-1;
}else return i;
}
}
return -1;
}
int main(){
scanf("%lld",&x);
bit[0]=1;
for(int i=1;i<=40;i++)bit[i]=bit[i-1]*2;
/*if(x==0){
printf("2\n");
printf("0\n");
return 0;
}*/
while(1){
int k=find(x);
//printf("%d\n",k);
if(k==-1)break;
if(k==-2)k=-1;
x=x^(bit[k+1]-1);
tot++;a[tot]=k+1;
x++;
k=find(x);
if(k==-1)break;
}
printf("%d\n",tot*2);
for(int i=1;i<=tot;i++)printf("%d ",a[i]);
}
C. Neko does Maths
C题是找(a+k) (b+k)的最小公倍数,一开始作差以后一直没有枚举差的因子.
gcd(?+?,?+?)=gcd(?−?,?+?).(也有一种方法是看一眼数据范围然后猜复杂度23333)
E题是个欧拉路径,离散以后建边,再转换成欧拉回路做
下次再碰到欧拉回路题要试着根据自己的理解盲打一遍,否则还要花时间磨合板子, (还是不习惯
#include<cstdio>
#include<map>
#include<algorithm>
#include<cstring>
#define ll long long
#define N 1002020
#define M 1001010
using namespace std;
int ma[N];
int n,m,tot=0,d[N],b[N],c[N],ru[N],g[N],v[M<<1],w[M<<1],vis[M<<1],nxt[M<<1],ed=1;
int ans[M],cnt=0;
void add(int x,int y,int z){
d[x]++;
//printf("%d %d\n",ma[x],ma[y]);
ed++;
v[ed]=y;w[ed]=z;nxt[ed]=g[x];
g[x]=ed;
}
void dfs(int x){
for(int &i=g[x];i;){
if(vis[i]){i=nxt[i];continue;}
//if(i%2)vis[i]=vis[i+1]=1;else vis[i]=vis[i-1]=1;
vis[i]=vis[i^1]=1;
// printf("%d %d\n",i,v[i]);
int vv=v[i];
dfs(v[i]);
//printf("===%d %d %d %d\n",x,vv,ma[x],ma[vv]);
cnt++;ans[cnt]=vv;
}
}
struct node{int x,id;}cc[N];
int cmp(node a,node b){return a.x<b.x;}
int main(){
scanf("%d",&n);
for(int i=1;i<n;i++)scanf("%d",&b[i]),tot++,cc[tot].x=b[i],cc[tot].id=i;
for(int i=1;i<n;i++)scanf("%d",&c[i]),tot++,cc[tot].x=c[i],cc[tot].id=n-1+i;
for(int i=1;i<n;i++){
if(b[i]>c[i]){
printf("-1\n");
return 0;
}
}
sort(cc+1,cc+tot+1,cmp);
int now=0;
for(int i=1;i<=tot;i++){
if(cc[i].x>cc[i-1].x)now++;
ma[now]=cc[i].x;
if(cc[i].id<=n-1)b[cc[i].id]=now;else c[cc[i].id-(n-1)]=now;
}
int x,y;
for(int i=1;i<n;i++){ru[b[i]]++;ru[c[i]]++;}
int sum=0;
int tt=now+1;
for(int i=1;i<=now;i++)if(ru[i]%2==1)sum++,b[n-1+sum]=i,c[n-1+sum]=tt;
if(sum%2){
printf("-1\n");return 0;
}
if(sum==0){
sum++;b[n-1+sum]=1;c[n-1+sum]=tt;
sum++;b[n-1+sum]=1;c[n-1+sum]=tt;
}
for(int i=1;i<=n+1;i++)x=b[i],y=c[i],add(x,y,i),add(y,x,-i);
for(int i=1;i<=tt;i++)if(d[i]&1){puts("-1");return 0;}
dfs(tt);
if(cnt!=n+1){
printf("-1\n");return 0;
}
for(int i=n+1;i>1;i--)printf("%d ",ma[ans[i]]);
}
D. Neko and Aki's Prank
后补的D,一开始感受了一下这个增长速度接近fibonacci,但是不死心敲了个n^2模拟,果然会爆ll
将合法的括号压进Trie以后,大致有点像状压的思想,因为确实有许多的子树形态都是重复的. 然后匹配的过程大部分做法都是贪心走,题解就直接dp,多了一维状态存进pair,表示根节点是否被匹配掉了
Codeforces Round #555 (Div. 3)
好像是第一次做了六个题,但其实是五个,C2是C1的hard,懒人就直接去写C2了.
Heltion还是太强了,不论是什么样子的round,总是能以一个极大的优势碾压我...
A. Reachable Numbers
算是签到题中长得比较吓人的,但是只要模拟就好了.最多就是花时间再感受一下复杂度,毕竟每个数字截掉末尾一串零以后下降的速度还是很快的..
B. Long Number
这道题题意看错了三次,太爽了.
You can perform the following operation no more than once: choose a non-empty contiguous subsegment of digits in ?a, and replace each digit ?x from this segment with ?(?)
没看到once;没看到contiguous;没看到each;导致写了不同做法的四个代码...笑死...
C2. Increasing Subsequence (hard version)
每次从头或尾取一个数字组成不下降序列,想了想好像不能dp做;那就直接贪心,把情况列清楚就可以敲起来了.
D. N Problems During K Days
吓一跳,这道题和上一道题之间隔了一个小时.
1<<kk的时候没有long long....刚刚也是看了一会儿才想起来...
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#define ll long long
#define N 602020
using namespace std;
int cas,m,flag=1;
ll n,K;
ll ans[N];
void GoGet(ll xx,ll kd,ll rest){
if(kd>K){
return;
}
ll k=K-kd+1,n=rest;
ll R=(n*2/k+1-k)/2;
ll kk;
if(k>60)kk=60;else kk=k;
kk=1ll<<kk;kk--;
ll L=ceil((double)n/(kk));
L=max(L,xx);
ans[(int)kd]=L;
if(L>R){
flag=-1;
return;
}
GoGet(L+1,kd+1,rest-L);
}
int main(){
scanf("%lld%lld",&n,&K);
ll R=(n*2/K+1-K)/2;
ll kk;if(K>60)kk=60;else kk=K;
kk=1ll<<kk;kk--;
ll L=ceil((double)n/(kk));
if(L>R){
printf("NO\n");
return 0;
}
GoGet(L,1,n);
if(flag==-1){
printf("NO\n");
return 0;
}
printf("YES\n");
for(int i=1;i<=(int)K;i++)printf("%lld ",ans[i]);
return 0;
}
E. Minimum Array
E其实不难,在只需要翻译做法的情况下,十几分钟就敲完了.
F. Maximum Balanced Circle
F好好想也不难,对于要构成的相邻高度不超过1的要求,就只要two pointers找到区间,然后也没了.
G. Inverse of Rows and Columns
那G对我来说还是不简单的,毕竟没有bitset这个意识,也很容易走火入魔到其它的做法之中...
1.枚举结果矩阵,共n*m种,设为B
2.把初始矩阵A和结果矩阵B异或一下,得到矩阵C
3.设r[i]表示第i行是否flip,c[i]表示第i行是否flip
对于矩阵C的每一个位置c[i][j],可以有r[i] xor c[j] == c[i][j]
然后我们可以发现 不妨设r[1]为0,因为如果设r[1]为1会得到一组对称的解,所以无所谓
那么我们假设r[1]为0,你会发现,可以确定所有的c[i]
4.现在我们手里握着所有的c[i]和r[1],随便选一列就可以算出一组可能的r[i]
5. 直接check的复杂度是O(n^4),可以用bitset加速
太熟练了....
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<bitset>
#define N 303
using namespace std;
int n,m;
int ma[N][N];
bitset<N> a[N],c[N],b[N],h0,h1;
int flag=-1;
void check(){
//printf("1111\n");
if(flag==1)return;
bitset<N>ans1,ans2,now;
for(int i=1;i<=n;i++)c[i]=a[i]^b[i];
ans2=h0^c[1];
for(int i=2;i<=n;i++){
now=h0^c[i];
//for(int j=1;j<=m;j++)cout<<'='<<b[i][j]<<' ';printf("\n");
if(now==ans2){
continue;
}
now=h1^c[i];
//printf("2222\n");
if(now==ans2){
ans1.set(i);
continue;
}
return;
}
puts("YES");
for(int i=1;i<=n;i++)cout<<ans1[i];cout<<"\n";
for(int i=1;i<=m;i++)cout<<ans2[i];
exit(0);
}
int main(){
//ios::sync_with_stdio(false);
//cin.tie(0);
//cout.tie(0);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&ma[i][j]);
if(ma[i][j]==1)a[i].set(j);
}
}
for(int i=1;i<=m;i++){
h1.set(i);
}
check();
for(int i=n;i>=1;i--){
for(int j=m;j>=1;j--){
b[i].set(j);
check();
}
}
if(flag==-1){puts("NO");}
return 0;
}