AtCoder Regular Contest 099
C - Minimization
题意:给出一个n的排列。每次操作可以使一段长度为K的连续子序列变成该序列的最小数。
求最少几次使得
分析:枚举包含1的序列是哪个,然后左右O(1)求答案。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define N 100050
int a[N],n,k,pos;
int main() {
scanf("%d%d",&n,&k);
int i;
for(i=1;i<=n;i++) {
scanf("%d",&a[i]);
if(a[i]==1) pos=i;
}
int ans=1<<30;
for(i=max(1,pos-k+1);i<=pos;i++) {
int j=i+k-1;
ans=min(ans,(i-1+k-2)/(k-1)+(n-j+k-2)/(k-1));
}
printf("%d\n",ans+1);
}
D - Snuke Numbers
题意:令S(n)表示n这个数各位之和。定义一个数n合法:所有m>n,都有n/S(n)<=m/S(m)。
输出前K个合法的数。
分析:显然所有99999这样的数都合法。
假设现在有一个数xyz999,这个数显然比xy9z99优,故在数字后面加的9的个数不降。
也就是是说每次加上$10^i$,其中i不降。需要判断这个数$+10^i$和$+10^{i+1}$谁更优,如果$10^{i+1}$更优就替换。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
int s(ll x) {
if(!x) return 0;
return x%10+s(x/10);
}
int main() {
int K;
scanf("%d",&K);
ll n=1,d=1;
printf("%d\n",1); K--;
while(K--) {
if(s(n+10*d)*(n+d)>(n+10*d)*s(n+d)) d*=10;
printf("%lld\n",n+=d);
}
}
E - Independence
题意:给出一个无向图,让你将它分成两部分使得,每部分的点互相有边相连。
问最少有几条相连的边。
分析:设分成S,T两个集合,答案等于siz(S)*(siz(S)-1)/2+siz(T)*(siz(T)-1)/2。
这个式子的意思是让我们最小化siz(S)和siz(T)的差的绝对值。
考虑对补图进行操作。补图上有边相连的两个点一定分别属于两个不同的集合。
对每个连通块进行染色,同时求出来每个连通块的两个集合分别有多少点。
然后就是个DP了,F[i][j]表示考虑前i个连通块,siz(S)-siz(T)的差为j是否合法。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
using namespace std;
#define GG puts("FUCK")
#define maxn 750
int map[750][750];
int n,m,a[750],b[750],tot;
int f[750][1550],vis[750];
void dfs(int x,int opt) {
int i; vis[x]=opt;
if(!opt) a[tot]++;
else b[tot]++;
for(i=1;i<=n;i++) {
if(map[x][i]) {
if(vis[i]==-1) {
dfs(i,opt^1);
}else if(vis[i]==opt) {
puts("-1"); exit(0);
}
}
}
}
int main() {
scanf("%d%d",&n,&m);
int i,j,x,y;
memset(vis,-1,sizeof(vis));
for(i=1;i<=n;i++) for(j=1;j<=n;j++) if(i!=j) map[i][j]=1;
for(i=1;i<=m;i++) {
scanf("%d%d",&x,&y); map[x][y]=map[y][x]=0;
}
for(i=1;i<=n;i++) {
if(vis[i]==-1) {
tot++;
dfs(i,0);
}
}
f[0][maxn]=1;
for(i=0;i<tot;i++) {
int del=a[i+1]-b[i+1];
for(j=0;j<=maxn+maxn;j++) {
if(f[i][j]) {
if(j>=del) f[i+1][j-del]=1;
if(j+del<=maxn+maxn) f[i+1][j+del]=1;
}
}
}
int mn=1<<30;
for(i=maxn;i<=maxn+maxn;i++) {
if(f[tot][i]) {
mn=i-maxn; break;
}
}
for(i=maxn;i>=0;i--) {
if(f[tot][i]) {
mn=min(mn,maxn-i); break;
}
}
int s=(n+mn)>>1,t=n-s;
printf("%d\n",s*(s-1)/2+t*(t-1)/2);
}
F - Eating Symbols Hard
题意:给你一个字符串表示操作。
+表示在指针对应位置上的值+1
-表示在指针对应位置上的值-1
>表示把指针右移1位。
<表示把指针左移1位。
假设按原串操作后序列为A。
求有多少个子串使得操作后的序列B等于A。
分析:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <map>
using namespace std;
typedef long long ll;
#define GG puts("FUCK")
#define N 500050
#define mr(x,y) make_pair(x,y)
inline char nc() {
static char buf[100000],*p1,*p2;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
int rd() {
int x=0; char s=nc();
while(s<'0'||s>'9') s=nc();
while(s>='0'&&s<='9') x=(x<<3)+(x<<1)+s-'0',s=nc();
return x;
}
char rc() {
char s=nc();
while(s!='+'&&s!='-'&&s!='>'&&s!='<') s=nc();
return s;
}
int mod1=998244353,base1=19260817,inv1;
int mod2=353448299,base2=20000003,inv2;
int h1[N],mi1[N],imi1[N],p[N],n,C;
int h2[N],mi2[N],imi2[N];
map<pair<int,int>,int>mp;
int qp(int x,int y,int p) {
int re=1;
for(;y;y>>=1,x=ll(x)*x%p) if(y&1) re=ll(re)*x%p;
return re;
}
int main() {
inv1=qp(base1,mod1-2,mod1);
inv2=qp(base2,mod2-2,mod2);
n=rd(); char str;
int i;
for(mi1[0]=imi1[0]=mi2[0]=imi2[0]=i=1;i<=(n<<1);i++) {
mi1[i]=ll(mi1[i-1])*base1%mod1;
imi1[i]=ll(imi1[i-1])*inv1%mod1;
mi2[i]=ll(mi2[i-1])*base2%mod2;
imi2[i]=ll(imi2[i-1])*inv2%mod2;
}
p[0]=n;
for(i=1;i<=n;i++) {
str=rc();
if(str=='+') {
p[i]=p[i-1];
h1[i]=(h1[i-1]+mi1[p[i]])%mod1;
h2[i]=(h2[i-1]+mi2[p[i]])%mod2;
}else if(str=='-') {
p[i]=p[i-1];
h1[i]=(h1[i-1]-mi1[p[i]]+mod1)%mod1;
h2[i]=(h2[i-1]-mi2[p[i]]+mod2)%mod2;
}else if(str=='>') {
p[i]=p[i-1]+1;
h1[i]=h1[i-1]; h2[i]=h2[i-1];
}else {
p[i]=p[i-1]-1;
h1[i]=h1[i-1]; h2[i]=h2[i-1];
}
mp[mr(h1[i],h2[i])]++;
}
ll ans=0;
for(i=1;i<=n;i++) {
int d=p[i-1]-n,t1=h1[n],t2=h2[n];
if(d>=0) t1=ll(t1)*mi1[d]%mod1,t2=ll(t2)*mi2[d]%mod2;
else t1=ll(t1)*imi1[-d]%mod1,t2=ll(t2)*imi2[-d]%mod2;
t1=(t1+h1[i-1])%mod1;
t2=(t2+h2[i-1])%mod2;
ans+=mp[mr(t1,t2)];
mp[mr(h1[i],h2[i])]--;
}
printf("%lld\n",ans);
}