codeforces 597 div2 ABCDF
codeforces 589 div2
A:Good ol' Numbers Coloringhttp://codeforces.com/contest/1245/problem/A
观察样例发现大概是 \(gcd(a,b) \neq 1\)的时候是无限,试了下A了 面向样例编程
除了cf应该不能这么意识流编程 正赛的时候这一两分钟也没那么重要
B: Restricted RPS
中等复杂的模拟题,但我写的时候一直wa,换了三种策略都没成,后来在广神的帮助下找到了是输出字符数组没有加结束符导致每次多样例的输出就会多很多东西,这种神奇的bug我还真是第一次遇到,记录一下。
#include <bits/stdc++.h>
using namespace std;
char l[10001],out[10001];
int main(){
//freopen("test.in","r",stdin);
//freopen("test.out","w",stdout);
int t,a,b,c,n,ans;
cin>>t;
while(t--){
cin>>n;
cin>>a>>b>>c;
cin>>l;
for(int i=0;i<n;i++){
out[i]='0';
}
ans=0;
for(int i=0;i<n;i++){
if(l[i]=='R' && b>0){b--;ans++;out[i]='P';}
if(l[i]=='P' && c>0){c--;ans++;out[i]='S';}
if(l[i]=='S' && a>0){a--;ans++;out[i]='R';}
}
//cout<<out<<endl;
for(int i=0;i<n;i++){
if(out[i]=='0'){
if(l[i]=='R')
if(a>0){a--;out[i]='R';}
else {c--;out[i]='S';}
if(l[i]=='S')
if(c>0){c--;out[i]='S';}
else {b--;out[i]='P';}
if(l[i]=='P')
if(b>0){b--;out[i]='P';}
else {a--;out[i]='R';}
}
}
if(n%2==0 && ans>=(n/2)){
cout<<"YES"<<endl;
for(int i=0;i<n;i++)printf("%c",out[i]);
cout<<endl;
}
else if(n%2==1 && ans>(n/2)){
cout<<"YES"<<endl;
for(int i=0;i<n;i++)printf("%c",out[i]);
cout<<endl;
}
else cout<<"NO"<<endl;
}
return 0;
}
总结下就是算法没有问题但是wa得很靠前的时候,还是要注意下像输入输出啊预处理啊这种东西,想起来秦皇岛哪个暴力dp也是因为预处理的字符表有问题疯狂wa。
C Constanze's Machine
题意:
规则1:字符串中的m会被写成nn,w写成uu
输入为原字符串经过规则1转化而来的字符串,问原字符串有多少种可能。
思考:
1.若给定串中有m或w,则出错,ans=0
2.分块
将连续的(大于等于2个)的u/n连续子串分开,每个长度为 \(l1,l2,l3...lm\) 容易发现对于每个子串,
ans[li]=ans[li-1]-ans[i-2];
斐波那契啊这是!那这下就解决了
#include<bits/stdc++.h>
using namespace std;
const long long mod = 1000000007;
long long fib[201111],pre[2000011];
char a[200011];
int main(){
fib[0]=1;fib[1]=1;
for(int i=2;i<100212;i++){fib[i]=(fib[i-1]+fib[i-2])%mod;}
cin>>a;
long long len=strlen(a),pos=0,num=0,ans=1;
for(int i=0;i<len;i++)if(a[i]=='w' || a[i]=='m'){cout<<'0'<<endl;return 0;}
while(pos<len){
if(a[pos]=='u' && a[pos+1]=='u'){
while(a[pos]=='u' && pos<len){
pos++;
pre[num]++;
}
num++;
}
else if(a[pos]=='n' && a[pos+1]=='n'){
while(a[pos]=='n' && pos<len){
pos++;
pre[num]++;
}
num++;
}
else pos++;
}
if(num==0){cout<<1<<endl;return 0;}
for(int i=0;i<num;i++)ans = (long long) ans * fib[ pre[i]] % mod;
cout<<ans<<endl;
return 0;
}
D: Shichikuji and Power Grid
做的时候并没有什么很好的思路果然还是自己菜qaq集训室有人吼了一句最小生成树,但是想了想并不知道解决出在哪些点建立电厂的这个前置问题;再加上b题浪费了过于多的时间,被迫放弃这个D。补题的时候看到一个聚聚写的博客简简单单提了一句超级根,一语点醒梦中人;只要建立超级源点到每个点的权值作为c[i],就可以巧妙地使建立电站和连接电网的价值转化为一个问题,从而跑个最小生成树就ok了。其实超级源点这个东西以前用的还是很多的,我甚至还给zz和瓜神说过这个玩意儿,这次还是没想到有点不应该。
这里贴一个讲超级源点的blog:https://blog.csdn.net/qq_40772692/article/details/83090675
代码
#include<bits/stdc++.h>
#define ll long long
#define maxn 2005
using namespace std;
int n;
ll X[maxn],Y[maxn],c[maxn],k[maxn];
struct edge
{
int u,v;
ll w;
edge(int U=0,int V=0,ll W=0):u(U),v(V),w(W){}
}e[maxn*maxn];
int fa[maxn];
bool operator < (edge A,edge B){return A.w<B.w;}
int find(int x)
{
if(fa[x]==x)return x;
return fa[x]=find(fa[x]);
}
vector<int> A;
vector< pair<int,int> >B;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;++i)scanf("%I64d%I64d",&X[i],&Y[i]);
for(int i=1;i<=n;++i)scanf("%I64d",&c[i]);
for(int i=1;i<=n;++i)scanf("%I64d",&k[i]);
int cnt=0;
for(int i=0;i<=n;++i)fa[i]=i;
for(int i=1;i<=n;++i)e[++cnt]=edge(0,i,c[i]);
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)if(i!=j)e[++cnt]=edge(i,j,(k[i]+k[j])*(abs(X[i]-X[j])+abs(Y[i]-Y[j])));
sort(e+1,e+cnt+1);
ll ans=0;
for(int i=1;i<=cnt;++i)
{
int u=e[i].u,v=e[i].v;
if(find(u)==find(v))continue;
fa[find(v)]=find(u);
ans+=e[i].w;
if(!u)A.push_back(v);
else B.push_back(make_pair(u,v));
}
printf("%I64d\n",ans);
printf("%d\n",A.size());
for(auto p: A)printf("%d ",p);
puts("");
printf("%d\n",B.size());
for(auto p: B)printf("%d %d\n",p.first,p.second);
}
E Hyakugoku and Ladders
概率dp,待补,这个当成专题叭,听说是道不难的概率dp
F: Daniel and Spring Cleaning
个人还是比较怕这种建立在数位运算上的题的,可能是对这些不太敏感不怎么能分析的出来。
分析
如果 \(x+y=x⊕y\) 则 $x∗y=0 $
如果想数位dp的话,这其实是道挺板的题,牛客多校有比这个难得多的,有机会还是多补一点叭
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll dp[40][2][2][2][2];
int abit[33],bbit[33];
ll dfs(int len,int lim1,int lim2,int z1,int z2){
if(len==-1)return 1;
if(dp[len][lim1][lim2][z1][z2]!=-1)return dp[len][lim1][lim2][z1][z2];
ll ans=0;
int up1=lim1?abit[len]:1;
int up2=lim2?bbit[len]:1;
for(int i=0;i<=up1;i++){
for(int j=0;j<=up2;j++){
if((i+j)==(i^j)){
ans+=dfs(len-1,lim1&&i==up1,lim2&&j==up2,z1||i!=0,z2||j!=0);
}
}
}
dp[len][lim1][lim2][z1][z2]=ans;
return ans;
}
ll solve(ll a,ll b){
memset(dp,-1, sizeof(dp));
for(int i=30;i>=0;i--){
abit[i]=a>>i&1;
bbit[i]=b>>i&1;
}
dfs(30,1,1,0,0);
}
ll t,l,r;
int main(){
ios::sync_with_stdio(false);
cin>>t;
ll a,b,c;
while (t--){
cin>>l>>r;
if(l==0){
a=slove(r,r);
cout<<a<<endl;
continue;
}
a=solve(r,r);
b=solve(l-1,l-1);
c=solve(l-1,r);
cout<<a+b-c-c<<endl;
}
}
分析2
这道题也可以直接按题解里面的递推式来算,看了题解还是大脑空空,头挺大的
有两个关键的式子:
有了这两个死也想不到的式子,就可以开始愉快的递推了
l为奇数:
r为奇数
贴个标程:
#include<bits/stdc++.h>
using namespace std;
int f(int a, int b)
{
int ret = 0;
int zeroes = 0;
for (int i = 1; i <= b; i <<= 1)
{
if (b & i)
{
b ^= i;
if (!(a & b))
ret += 1 << zeroes;
}
if (!(a & i))
zeroes++;
}
return ret;
}
long long rec(int a, int b)
{
if (a == b)
return 0;
if (a == 0)
return 2 * b - 1 + rec(1, b);
long long ret = 0;
if (a & 1)
{
ret += 2 * (f(a, b) - f(a, a));
a++;
}
if (b & 1)
{
ret += 2 * (f(b - 1, b) - f(b - 1, a));
b--;
}
return ret + 3 * rec(a / 2, b / 2);
}
int main()
{
int t;
for (cin >> t; t--;)
{
int a, b;
cin >> a >> b;
cout << rec(a, b + 1) << '\n';
}
return 0;
}