【CF】Codeforces Round #542 [Alex Lopashev Thanks-Round] (Div. 1)
orz orz orz
CF
A1 A2
给你n个点,m个糖,告诉你这个糖要从x点拿到y点,每次经过一个城市只能拿一个糖,但可以放任意数量的糖 问你从任意一个点开始走,最少要走几步,只能从1->2->3->4……->n->1 同一道题数据范围不同。。用同一份代码都能A。#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstring>
#include<queue>
#include<stack>
#include<vector>
using namespace std;
int n,m;
int jl(int x,int y) {
if(x<=y) return y-x;
return y+n-x;
}
int CNT[5005],ZJ[5005];
int ans;
int main() {
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) ZJ[i] = n;
for(int i=1;i<=m;i++) {
int a,b; scanf("%d%d",&a,&b);
CNT[a]++; ZJ[a] = min(ZJ[a],jl(a,b));
}
for(int i=1;i<=n;i++) {
ans = 0;
if(CNT[i]) ans = max(ans,(CNT[i]-1)*n+ZJ[i]);
for(int j=1;j<=n;j++) {
if( (!CNT[j])||(i==j) ) continue;
ans = max(ans,jl(i,j)+(CNT[j]-1)*n + ZJ[j] );
}
printf("%d ",ans);
}
}
B
给了你一个假贪心,你要构造一组数据把它卡掉,并且使得这组数据的结果和贪心的结果之差恰好为k. 随便怎么构都可以啦orz.有一种方法是前面全构造0然后又加一个-1之后全放正数。这样假贪心的结果一定是后面正数的总和,然后我们的真贪心的结果是总长度×(正数总和-1),稍微构造一下就可以了。#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstring>
#include<queue>
#include<stack>
#include<vector>
#define int long long
using namespace std;
int k;
int CD;
bool ok(int X,int cd) {
int chang = cd + CD;
if(chang>2000) return 0;
X++;
if(X>((int)1e6)*CD) return 0;
printf("%I64d\n",chang);
for(int i=1;i<cd;i++) printf("0 ");
printf("-1 ");
for(int i=1;i<=CD;i++) {
printf("%I64d ",min(1000000LL,X));
X -= min(1000000LL,X);
}
return 1;
}
main() {
cin>>k;
for(int cd=1;cd<=1999;cd++) {
int K = cd+k;
CD = cd;
for(int i=1;1ll*i*i<=K;i++) {
if(K%i) continue;
if(ok(i,K/i)) {
return 0;
}
if(ok(K/i,i)) {
return 0;
}
}
}
puts("-1");
}
C
长度为1,2,3,4的二进制串一共有30个,除了0011,0101,1110,1111之外,每一个都对应着一个字母。 现在给定一个串S,对于每一个i,询问S[1,i]中的所有子串中,本质不同的对应着一个英文字母串的拆分方案数。 考虑其实两个问题,首先对于一种子串询问拆分的方案,其次对于本质相同的子串答案只计算贡献一次。 第一问f[i][j]表示区间[i,j]可以拆分的。枚举最后的字母是什么就可以了。 第二问trie,SAM,hash啥的都可以干#include<stdio.h>
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
const int mod = 1e9+7;
int add(int x,int y) { x+=y; return x>=mod?x-mod:x; }
int sub(int x,int y) { x-=y; return x<0?x+mod:x; }
int mul(int x,int y) { return 1ll*x*y%mod; }
int m;
int ch[4500005][2],tot=1;
int f[3005][3005];
int a[3005],ans;
bool PD(int l,int r) {
if(r-l+1<4) return 1;
if(a[l]==0&&a[l+1]==0&&a[l+2]==1&&a[l+3]==1) return 0;
if(a[l]==0&&a[l+1]==1&&a[l+2]==0&&a[l+3]==1) return 0;
if(a[l]==1&&a[l+1]==1&&a[l+2]==1&&a[l+3]==0) return 0;
if(a[l]==1&&a[l+1]==1&&a[l+2]==1&&a[l+3]==1) return 0;
return 1;
}
int main() {
scanf("%d",&m);
for(int i=1;i<=m;i++) scanf("%d",&a[i]);
for(int i=1;i<=m;i++) {
for(int j=i;j>=(max(i-3,1));j--) {
if(PD(j,i)) {
f[j][i] = add(f[j][i],1);
for(int k=j-1;k>=1;k--) {
f[k][i] = add(f[k][i],f[k][j-1]);
}
}
}
int o = 1;
for(int j=i;j>=1;j--) {
if(!ch[o][a[j]]) {
ch[o][a[j]] = ++tot;
ans = add(ans,f[j][i]);
}
o = ch[o][a[j]];
}
printf("%d\n",ans);
}
}
D
把一个数组分成不相交的若干段,使得每一段中出现了恰好1次的数的个数至多是k个。 求划分方案数。 看这位大佬的ba无梦之梦/*
if ai first v = 1
ai last = -1
ai second last = 0
S[i] = \sum vj (j<=i)
dp[i] = \sum j(0,i-1): dp[j] (Sj>=Si-k)
*/
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
const int mod = 998244353;
const int maxn = 1e5+5;
const int maxk = 350;
int add(int x,int y) { x+=y; return x>=mod?x-mod:x; }
int sub(int x,int y) { x-=y; return x<0?x+mod:x; }
int mul(int x,int y) { return 1ll*x*y%mod; }
void upd(int &x,int y) { x=add(x,y); }
int blk,n,k,ks,blo[maxn];
int MX[maxk],tag[maxk];
int S[maxk][maxn],sv[maxn],L[maxk],R[maxk];
int dp[maxn];
int V[maxn];
void build(int o) {
int mixx = 0x3f3f3f3f; int maxx = -0x3f3f3f3f;
for(int i=L[o];i<=R[o];i++) {
mixx = min(mixx,sv[i]);
maxx = max(maxx,sv[i]);
}
MX[o] = maxx-mixx;
tag[o] += mixx;
fill(S[o],S[o]+MX[o]+2,0);
for(int i=L[o];i<=R[o];i++) {
sv[i] -= mixx;
upd(S[o][sv[i]],dp[i]);
}
for(int i=MX[o];i>=0;i--) upd(S[o][i],S[o][i+1]);
}
void change1(int o,int l,int r,int x) {
for(int i=l;i<=r;i++) sv[i] = sv[i]+x;
}
void modify(int l,int r,int x) {
if(x==V[l]) return;
int orz = x-V[l];
V[l] = x;
if(blo[l]==blo[r]) {
change1(blo[l],l,r,orz);
return;
}
for(int i=blo[l]+1;i<blo[r];i++) tag[i]+=orz;
change1(blo[l],l,R[blo[l]],orz);
build(blo[l]);
change1(blo[r],L[blo[r]],r,orz);
}
int nt[maxn],lst[maxn];
int query(int o,int V) {
V -= tag[o];
if(V>MX[o]) return 0;
if(V<0) return S[o][0];
return S[o][V];
}
int main() {
scanf("%d%d",&n,&k);
ks = 1; blk = sqrt(n);
for(int i=1;i<=n;i++) {
blo[i] = ks;
R[ks] = i;
if(i%blk==0) ks++,L[ks]=i+1;
}
if(n%blk==0) ks--;
for(int i=1;i<=n;i++) {
int val; scanf("%d",&val);
nt[i] = lst[val]; lst[val] = i;
int a = nt[i]; int b = nt[nt[i]];
sv[i] = sv[i-1]; if(blo[i]!=blo[i-1]) sv[i] += tag[blo[i-1]];
if(a) modify(a,i,-1);
if(b) modify(b,i,0);
sv[i]++;V[i] = 1;
if(sv[i]<=k) dp[i] = 1;
for(int j=1;j<blo[i];j++) upd(dp[i],query(j,sv[i]-k));
for(int j=L[blo[i]];j<i;j++) if(sv[j]>=sv[i]-k) upd(dp[i],dp[j]);
if(i==R[blo[i]]) build(blo[i]);
}
printf("%d",dp[n]);
}
E
有趣地构造。强制1当根,然后找出每个点的siz.siz从小到大排序之后,对于每个点当父亲的情况,从前面siz比自己小的并且没有父亲的点中选,考虑二分不断地找出所有可以当他儿子的点,每一次log都一定有一个点找到了父亲,O(nlogn)#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<set>
#define pr pair<int,int>
#define fi first
#define se second
using namespace std;
const int maxn = 505;
int fa[maxn],qe[maxn];
int n,sz[maxn];
void fl() {
fflush(stdout);
}
void pt(int x) {
printf("%d\n",x);
}
int yo() {
fl();
int x; scanf("%d",&x);
return x;
}
pr a[maxn];
int ST[maxn];
set<int>se;
int GAOIT(int L,int R,int owo) {
pt(R-L+1);
for(int i=L;i<=R;i++) pt(ST[i]);
pt(1); pt(1);
pt(owo);
fl();
return yo();
}
int main() {
n = yo();
sz[1] = n;
a[1] = pr(n,1);
for(int i=2;i<=n;i++) {
pt(1); pt(1);
pt(n-1);
for(int j=2;j<=n;j++) {
pt(j);
}
pt(i);
fl();
sz[i] = yo();
a[i] = pr(sz[i],i);
}
sort(a+1,a+1+n);
for(int i=1;i<=n;i++) {
int tp = 0;
for(auto o:se) {
ST[++tp] = o;
}
for(int j=1;j<=tp;) {
if(!GAOIT(j,tp,a[i].se)) break;
int L = j; int R = tp; int mid , ans = 0;
while(L<=R) {
int mid = (L+R)>>1;
if(GAOIT(L,mid,a[i].se)) ans = mid , R = mid - 1;
else L = mid + 1;
}
fa[ST[ans]] = a[i].se;
se.erase(ST[ans]);
j = ans + 1;
}
se.insert(a[i].se);
}
puts("ANSWER");
for(int i=2;i<=n;i++) {
printf("%d %d\n",i,fa[i]);
}
}