Codeforces Round #450 (Div. 2)
A:水
#include <bits/stdc++.h>
using namespace std;
int main()
{
int a=0,b=0;
int n;
cin >> n;
while(n--)
{
int x,y;
cin >> x >> y;
if(x<0) ++a;
else ++b;
}
if(a<=1||b<=1) cout << "Yes" << endl;
else cout << "No" << endl;
return 0;
}
B:
题意是求出
c
在
求小数部分可以用求长除法的过程,因为分母是
b
,所以余数最多有
#include <bits/stdc++.h>
using namespace std;
int main()
{
int a,b,c,ans=0;
cin >> a >> b >> c;
int k=b;
while(k--)
{
++ans;
a*=10;
if(a/b==c)
{
printf("%d\n",ans);
return 0;
}
a%=b;
}
puts("-1");
return 0;
}
C:
题意是排列中满足
aj<ai
对于所有
j<i
的
ai
是一个record,问删除哪一个数后使得数列的record数量最大。
可以用 set
维护
ai
之前的所有
aj
,扫一遍可以求出没删任何数时
ai
是否为record,用
b[i]
表示,那么
B=∑b[i]
就是所有没删之前record的数量。
一个数变为record的条件是它之前只有一个数比它大,且这个数被删除。那么同样可以用 set
维护,设删除一个数后有多少个在它后面的数从非record变为record,然后求
max(B−b[i]+c[i])
就是答案。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+7;
int a[N],p[N],c[N],b[N];
int main()
{
int n;
scanf("%d",&n);
set<int> s;
for(int i=1;i<=n;++i)
{
scanf("%d",&a[i]);
p[a[i]]=i;
s.insert(a[i]);
}
for(int i=n;i>=1;--i)
{
s.erase(a[i]);
auto it = s.upper_bound(a[i]);
if(it == s.end()) b[i]=1;
else
{
++it;
if(it == s.end())
{
--it;
c[p[*it]]++;
}
}
}
int ans = 1000000,cnt = 0,cc=0;
for(int i=1;i<=n;++i) cc+=b[i];
for(int i=1;i<=n;++i)
{
if(c[i]+cc-b[i]>cnt||(c[i]+cc-b[i]==cnt&&a[i]<ans))
{
ans=a[i];
cnt=c[i]+cc-b[i];
}
}
printf("%d\n",ans);
return 0;
}
D:
题意可以转化为求有多少个数列满足gcd为1且和为
yx
。
设
f(t)
为有多少个数列满足gcd为1且和为
t
。
设
可以得到下式:
那么 f(t)=g(t)−∑d|t且d≠1f(td) 。
又因为 g(t)=2t−1 。且 t 的因数是开立方级别的。可以先预处理出
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
ll ans;
ll powm(ll a, ll b)
{
ll c = 1;
while(b)
{
if(b&1) c=c*a%mod;
a=a*a%mod;
b>>=1;
}
return c;
}
int main()
{
int x,y;
scanf("%d %d",&x,&y);
if(y%x)
{
puts("0");
return 0;
}
y/=x;
vector<int> a;
for(int i=1;i*i<=y;++i)
{
if(y%i==0)
{
a.push_back(i);
if(i*i!=y) a.push_back(y/i);
}
}
vector<ll> dp(a.size());
sort(a.begin(), a.end());
int n = a.size();
for(int i=0;i<n;++i)
dp[i]=powm(2, a[i]-1);
for(int i=0;i<n;++i)
for(int j=i+1;j<n;++j)
if(a[j]%a[i]==0) dp[j]=(dp[j]-dp[i]+mod)%mod;
printf("%I64d\n",dp.back());
return 0;
}
E:
可以求出连续的从
i
开始 abab...
数量
求出问号前缀和
pre[i]
。
然后就变成dp了。
答案就是 dp[n].second 。
max的定义是数量最大消耗问号最小。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+7;
char s[N];
struct Node
{
int c,w;
Node():c(0),w(0){}
Node(int c,int w):c(c),w(w){}
bool operator < (const Node & r) const
{
return c<r.c||(c==r.c&&w>r.w);
}
};
Node dp[N];
int a[N]; //consecutive 'aba...'
int b[N]; //consecutive 'bab...'
int p[N]; //prefix sum of count of '?'
int main()
{
int n,m;
scanf("%d",&n);
scanf("%s",s+1);
scanf("%d",&m);
for(int i=n;i>=1;--i)
{
if(s[i]=='a')
{
a[i]=b[i+1]+1;
b[i]=0;
}
else if(s[i]=='b')
{
b[i]=a[i+1]+1;
a[i]=0;
}
else
{
a[i]=b[i+1]+1;
b[i]=a[i+1]+1;
}
}
for(int i=1;i<=n;++i)
p[i]=p[i-1]+(s[i]=='?');
for(int i=0;i<n;++i)
{
dp[i+1]=max(dp[i+1],dp[i]);
if(a[i+1]>=m&&i+m<=n)
dp[i+m]=max(dp[i+m],Node(dp[i].c+1,dp[i].w+p[i+m]-p[i]));
}
printf("%d\n",dp[n].w);
return 0;
}