Codeforces Round #785 (Div. 2) A~F

小细节卡的挺难受呀
A. Subtle Substring Subtraction

Alice肯定一下取走尽可能多的数

/*input
5
aba
abc
cba
n
codeforces

*/
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
char s[N];
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		int sum=0;
		scanf("%s",s+1);
		int l=strlen(s+1);
		for(int i=1;i<=l;i++) sum+=s[i]-'a'+1;
		if(l%2==0)	cout<<"Alice "<<sum<<endl;
		else{
			int L=sum-min(s[l]-'a'+1,s[1]-'a'+1);
			if(L>sum-L)cout<<"Alice "<<2*L-sum<<endl;
			else cout<<"Bob "<<sum-2*L<<endl;
		}
	}
}

每个字母都有可能成为多一的那个,但是任意两个相邻相同字母之间都存在其他字母的时候那么他就不会是那个字母

B. A Perfectly Balanced String?

/*input
5
aba
abb
abc
aaaaa
abcba

*/
#include<bits/stdc++.h>
using namespace std;
int a[30];
bool c[30];
char s[200010];
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		int sum=0;
		scanf("%s",s+1);
		int l=strlen(s+1);
		for(int i=0;i<30;i++) a[i]=c[i]=0;
		for(int i=1;i<=l;i++) c[s[i]-'a']=1;
		for(int i=0;i<30;i++) sum+=c[i],c[i]=0;
		bool ans=1;
		for(int i=1;i<=l;i++)
		{
			int p=s[i]-'a';
			//cout<<i-a[p]<<endl;
			if(c[p]&&i-a[p]<sum) ans=0;
			a[p]=i;
			c[p]=1;
		}
		if(ans) puts("YES");
		else    puts("NO");
	}
}

C. Palindrome Basis

动态规划,枚举构成最大值

/*input
2
5
12
*/
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
vector<int> a;
int sz;
bool check(int x){
	vector<int> b;
	while(x){
		b.push_back(x%10);
		x/=10;
	}
	int SZ=b.size();
	for(int i=0;i<SZ/2;i++)
		if(b[i]!=b[SZ-i-1]) return false;
	return true;
}
int ans[40010];
int main()
{
	for(int i=1;i<=40000;i++) if(check(i)) a.push_back(i);sz=a.size();
	ans[0]=1;
	for(int i=0;i<sz;i++)
	{
		for(int j=a[i];j<=40000;j++)
		{
			ans[j]+=ans[j-a[i]];
			if(ans[j]>=mod) ans[j]-=mod;
		}
	}
	int t;
	cin>>t;
	while(t--)
	{
		int n;
		cin>>n;
		cout<<ans[n]<<endl;
	}
}

D. Lost Arithmetic Progression

暴力枚举因数计算结果
yy不是y的倍数或者两个序列并不同轨那么也会不会交的,答案为0
如果C在B的边缘那么答案是无穷的
可行区间左右对称,平方加和即可

/*input
1
-428244446 20449344 86035324
-39706910 368088192 781991

*/

#include<iostream>
using namespace std;

typedef long long ll;
ll gcd(ll x,ll y)
{
	while(y) y^=x^=y^=x%=y;
	return x;
}
const int mod=1e9+7;
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		ll x,y,z;
		ll xx,yy,zz;
		cin>>x>>y>>z;
		cin>>xx>>yy>>zz;
	
		if(yy%y!=0||xx<x||x+(z-1)*y<xx+(zz-1)*yy||(x-xx)%y!=0) cout<<0<<endl;
		else if(x>xx-yy||x+(z-1)*y<xx+zz*yy) cout<<-1<<endl;
		else
		{
			ll g=yy/y;
			
			while(g*y/gcd(g,y)!=yy) g=yy/y*gcd(g,y);

			ll p=y/gcd(y,g);
			ll ans=0;

			for(ll i=1;i*i<=p;i++)
			{
				if(p%i==0)
				{
					if(p/i==i) ans+=i*i;
					else ans+=i*i+p/i*p/i;
					ans%=mod;
				}
			}
			cout<<ans<<endl;
		}
		
	}
}

E. Power or XOR?

taps 每段区间的长度不会超过21
所以可以暴力的枚举每一段区间,每一段的区间指数<1e6,大的会被模掉,对答案不产生影响
对于每一段,通过组合数计算出现奇偶次数,偶数次XOR=0;对答案不产生影响,对于奇数次位置XOR1
组合数的奇偶性可以暴力求那一段可行区间的,也可以使用C(l,r)=C(l-1,r)+C(l-1,r-1);
+C(l,r…l)=C(l,r)+2*K+C(l,l);因此计算两边的奇偶性即可

补上一个高级的判定方法若l&r=r,则C为奇数,否则为偶数

/*input
2 1
1 2

*/
#include<iostream>
using namespace std;
typedef long long ll;
const int N=2e6+10;
const int MAX=1024*1024;
int c2[N],b[N],b2[N],ans[N],base;
ll pb[N];
bool f[31][N];
int pf[31][N];
bool check(int l,int r)
{
	if(r>l) return 0;
	if(r==0) return pf[l-base][l]&1;
	return (pf[l-base][l]-pf[l-base][r-1])&1;
}
bool check2(int l,int r)
{
	if(r>l) return 0;
	return !(c2[l]-c2[l-r]-c2[r]);
}
int ksm(int x,int y)
{
	int ans=1;
	while(y){
		if(y&1) ans=ans*x;
		y>>=1;
		x*=x;
	}
	return ans;
}

void cal(int l,int r,int cl,int cr)
{
	if(check(cl,cr)&&pb[r]-pb[l]+b2[l]<20){
		int idx=ksm(2,pb[r]-pb[l])*b[l];
		ans[idx]^=1;
	}
}
int read()
{
	int ans=0;
	char c=getchar();
	while(c==' '||c=='\n') c=getchar();
	while(c>='0'&&c<='9') ans=ans*10+c-'0',c=getchar();
	return ans;
}
int main()
{
	for(int i=1;i<N;i++){
		int p=i;
		c2[i]+=c2[i-1];
		while((p&1)==0) c2[i]++,p>>=1;
	}
	int n,k;
	cin>>n>>k;
	base=max(n-30,0);

	for(int i=max(0,n-30);i<=n;i++)
		for(int j=0;j<=n;j++){
			f[i-base][j]=check2(i,j);
			if(j==0) pf[i-base][j]=f[i-base][j];
			else pf[i-base][j]=pf[i-base][j-1]+f[i-base][j];
		}

	for(int i=1;i<=n;i++){
		b[i]=read();
		pb[i]=pb[i-1]+b[i];
		int p=b[i];p>>=1;
		while(p) b2[i]++,p>>=1;
	}
	if(k==0) cal(1,n,0,0);
	k=max(k,1);
	for(int j=1;j<min(n,25);j++) cal(1,j,n-j-1,k-1);
	for(int j=max(2,n-25);j<=n;j++) cal(j,n,j-2,k-1);
	k=max(k,2);
	for(int i=2;i<=n-1;i++)
		for(int j=1;j<=25&&i+j-1<n;j++)
			cal(i,i+j-1,n-j-2,k-2);
	bool zero=1;
	for(int i=N;i>=0;i--){
		if(ans[i]) zero=0;
		if(!zero) printf("%d",ans[i]);
	}
	if(zero) cout<<0;
	puts("");
}
/*input
3 0
3 1 2
*/
#include<iostream>
using namespace std;
typedef long long ll;
const int N=2e6+10;
const int MAX=1024*1024;
int c2[N],b[N],b2[N],ans[N],st[N];
ll pb[N];
bool check(int l,int r)
{
	if(r>l) return 0;
	if(l==0) return 1;
	if(r==0) return 0;
	return !(((l-1)&(r-1))^(r-1));
}
int ksm(int x,int y)
{
	int ans=1;
	while(y){
		if(y&1) ans=ans*x;
		y>>=1;
		x*=x;
	}
	return ans;
}

bool cal(int l,int r,int cl,int cr)
{
	if(pb[r]-pb[l]+b2[l]>=20) return 0;
	if(check(cl,cr)){
		int idx=ksm(2,pb[r]-pb[l])*b[l];
		ans[idx]^=1;
	}
	return 1;
}
int read()
{
	int ans=0;
	char c=getchar();
	while(c==' '||c=='\n') c=getchar();
	while(c>='0'&&c<='9') ans=ans*10+c-'0',c=getchar();
	return ans;
}
int main()
{
	int n,k;
	cin>>n>>k;
	for(int i=0;(1<<i)<=MAX;i++) st[1<<i]=i;
	for(int i=1;i<=MAX;i++) if(!st[i]) st[i]=st[i-1];
	for(int i=1;i<=n;i++){
		b[i]=read();
		pb[i]=pb[i-1]+b[i];
		b2[i]=st[b[i]];
	}
	if(k==0) cal(1,n,0,0);
	k=max(k,1);
	for(int j=1;j<min(n,25);j++) if(!cal(1,j,n-j-1,k-1)) break;
	for(int j=n;j>=max(2,n-25);j--) if(!cal(j,n,j-2,k-1)) break;
	k=max(k,2);
	for(int i=2;i<=n-1;i++)
		for(int j=1;j<=25&&i+j-1<n;j++)
			if(!cal(i,i+j-1,n-j-2,k-2)) break;
	bool zero=1;
	for(int i=MAX;i>=0;i--){
		if(ans[i]) zero=0;
		if(!zero) printf("%d",ans[i]);
	}
	if(zero) cout<<0;
	puts("");
}

F. Anti-Theft Road Planning

我们尽量把高位相同放在一块
想办法让每个节点唯一代表一个值并且相邻两数的异或和尽可能小
对于32*32;把他分成四分,最高两位一致的放在四个角上
其次对于矩阵的四份做一个上下左右对称,这样位于边界上的数除了最高位不同以外,其他位相同
依次分型递推

#include<iostream>
using namespace std;
int s[50][50];
int mp[50][50][2];
int ans[2000][2];
void cp(int x,int y,int xx,int yy,int n,int p,int xj,int yj)
{
	for(int i=0;i<n;i++)
		for(int j=0;j<n;j++)
			s[xx+i*xj][yy+j*yj]=s[x+i][y+j]+p;
}
void build(int x)
{
	if(x==0) return ;
	build(x-1);
	cp(1,1,1,1<<x,(1<<(x-1)),1<<2*(x-1),1,-1);
	cp(1,1,1<<x,1,(1<<(x-1)),2<<2*(x-1),-1,1);
	cp(1,1,1<<x,1<<x,(1<<(x-1)),3<<2*(x-1),-1,-1);
}
int main()
{
	int n,k,idx=0;
	cin>>n;
	build(5);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			if(j>1) mp[i][j][0]=s[i][j]^s[i][j-1];
			if(i>1) mp[i][j][1]=s[i][j]^s[i-1][j];
			ans[s[i][j]][0]=i;
			ans[s[i][j]][1]=j;
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=2;j<=n;j++) cout<<mp[i][j][0]<<' ';
		puts("");
	}
	for(int i=2;i<=n;i++){
		for(int j=1;j<=n;j++) cout<<mp[i][j][1]<<' ';
		puts("");
	}
	cin>>k;
	while(k--)
	{
		int mod;
		cin>>mod;
		idx^=mod;
		cout<<ans[idx][0]<<' '<<ans[idx][1]<<endl;
	}	
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值