• AtCoder Regular Contest 099


    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
    ",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
    ",1); K--;
    	while(K--) {
    		if(s(n+10*d)*(n+d)>(n+10*d)*s(n+d)) d*=10;
    		printf("%lld
    ",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
    ",s*(s-1)/2+t*(t-1)/2);
    }
    

    F - Eating Symbols Hard

    题意:给你一个字符串表示操作。

    +表示在指针对应位置上的值+1

    -表示在指针对应位置上的值-1

    >表示把指针右移1位。

    <表示把指针左移1位。

    假设按原串操作后序列为A。

    求有多少个子串使得操作后的序列B等于A。

    分析:

    观察到操作的$S$序列可以用哈希的方法变成一个多项式。
    其中设$M$为一个大质数,$X$为一个$base$。对于字符串$S$,定义$t(S)$为其哈希值。
    有$t(S)=(sumlimits_{i}A_iX^{i})modM$
    在S前加入一个字符后,有:
    $t(0)=0$,为一个空串。
    $t(+S)=t(S)+1$
    $t(-S)=t(S)-1$
    $t(>S)=t(S)X$
    $t(<S)=t(S)X^{-1}$
    令$C$为整个序列的哈希值,也就是我们要统计有多少$(i,j)$使得$i$到$j$的哈希值为$C$
    处理出来前缀的系数,逆元的i次方和base的i次方。
    然后map一下。
    代码:
    #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
    ",ans);
    }
    
  • 相关阅读:
    [考试反思]0511省选模拟93:平衡
    [考试反思]0509省选模拟92:警示
    [考试反思]0508省选模拟91:小雨
    [考试反思]0507省选模拟90:信任
    [考试反思]0506省选模拟89:无事
    [专题总结]2-sat及题目&题解(3/5 complete)
    [考试反思]0505省选模拟88:滑稽
    [考试反思]0504省选模拟87:开花
    [考试反思]0502省选模拟86:恐惧
    [考试反思]0501省选模拟85:低落
  • 原文地址:https://www.cnblogs.com/suika/p/9252914.html
Copyright © 2020-2023  润新知