题目链接:https://codeforces.com/contest/1114
A题
题意: 三个人分别至少选x,y,z件物品,有三种物品数量分别为a,b,c,其中第一个人只能选第一种,第二个人不能选第三种,第三个人随意问能否满足三个人需求。
思想: 模拟
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
ll x,y,z;
ll a,b,c;
cin>>x>>y>>z;
cin>>a>>b>>c;
if(a>=x && b+(a-x)>=y && b+(a-x)-y+c>=z)
cout<<"YES\n";
else
cout<<"NO\n";
return 0;
}
B题
题意:要求把n个数的数列分成k份,每份至少有m个数,问这k份的前m大数之和的和最大值是多少,并要求给出一种构造方案。
思想:先排序出来m*k个最大的,然后每m个前m*k最大的数分成一组。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> P;
const int maxn = 2e5 + 10;
ll a[maxn];
int vis[maxn];
ll ans,num,num1,sum,n,m,k;
int main()
{
cin >> n >> m >> k;
for(int i = 1; i <= n; i++)
{
pair<int,int>p;
cin >> p.first;
p.second = i;
q.push(p);
}
for(int i = 1; i <= m * k; i++)
{
ans += q.top().first;
vis[q.top().second] = 1;
q.pop();
}
cout << ans << endl;
for(int i = 1; i <= n; i++)
{
num += vis[i];
if(num==m && k>1)
{
k--;
cout <<i<<" ";
num = 0;
}
}
cout << endl;
return 0;
}
C题
题意:给出 两个数n,b,n≤1e18,b≤1e12 问n!在b进制下有多少个后缀0
思想:考虑下,考虑下n!等于有多少可以凑出来b的倍数,然后考虑b可以由一些素因子构成,就变成了n!可以凑出来多少b的素因子。转换成n!由多少凑出来b的素因子,取一个最小值即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
ll a[maxn];
ll find(ll a,ll n)
{
ll ans=0;
while(n)
{
ans+=n/a;
n=n/a;
}
return ans;
}
int main()
{
ll n,b,ans=1e18;
scanf("%lld%lld",&n,&b);
ll t=sqrt(b);
for(ll i=2;i<=t;i++)
{
if(b%i==0)
{
ll cnt=0;
while (b%i==0)
{
++cnt;
b /= i;
}
ans = min(ans,find(i,n)/cnt);
}
}
if(b>1)
ans=min(ans,find(b,n));
cout<<ans<<endl;
return 0;
}
D 题
题意:给出一个n个数的数列(n≤5000),称一段相同的数为一个连通块,你每次可以选择一个连通块把它整体变成另一个数,问把整个数列变成同一个数的最少次数。
思想:DP转移,考虑等于左边界还是右边界。dp[i][j][0/1] 0代表i-j区间都等于a[i] 1代表i-j区间等于a[j]
dp[i][j][0]可以由dp[i+1][j][0]+a[i]!=a[i+1] 和 dp[i+1][j][1]+a[i]!=a[j]
dp[i][j][1]可以由dp[i][j-1][0]+a[i]!=a[j] 和 dp[i][j-1][1]+a[j-1]!=a[j]
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5000+10;
int a[maxn];
int dp[maxn][maxn][2];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=2;i<=n;i++)
{
for(int l=1;l<=n;l++)
{
int r=l+i-1;
if(r>n)
break;
dp[l][r][0]=min(dp[l+1][r][0]+int(a[l]!=a[l+1]),dp[l+1][r][1]+int(a[l]!=a[r]));
dp[l][r][1]=min(dp[l][r-1][1]+int(a[r]!=a[r-1]),dp[l][r-1][0]+int(a[l]!=a[r]));
}
}
printf("%d\n",min(dp[1][n][0],dp[1][n][1]));
return 0;
}
E 题
题意:给你一个长度为n的等差序列,现在打乱了,让你在60次交互次之内找到首项和等差。
思想:二分1-1e9 可以在30次的范围内找到最大值。然后随机选出来30个数和最大值的差值取gcd,就求出来了公差。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
map<ll,int>m;
mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
int main()
{
srand(time(0));
ll n,l=0,r=1e9,flag,ans,cnt=0;
cin>>n;
while(l<=r)
{
ll mid=(l+r)/2;
cout<<"> "<<mid<<endl<<endl;
cin>>flag;
if(flag)
l=mid+1;
else
r=mid-1;
cnt++;
}
ans=l;
ll s=0;
for(int i=0;i<min(30ll,n);i++)
{
ll t;
while(1)
{
t = rnd()%n+1;
if(m.find(t)==m.end())
{
m[t]=1;
break;
}
}
cout<<"? "<<t<<endl<<endl;
cin>>t;
s=__gcd(s,ans-t);
}
cout<<"! "<<ans-(n-1)*s<<" "<<s<<endl<<endl;
return 0;
}
F题
题意:有两种操作,一个是区间乘x,一个是询问区间积的欧拉值。
思想:线段树和压位。县单数维护区间乘,然后考虑素数对于区间积的欧拉有影响,300之内就62个素数,将其压位到Long long,线段树维护乘的时候同时将X分解素因子,然后或上即可。
ps:别人2s就行我硬跑3s,感觉写丑了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=4e5+10;
const ll mod = 1e9+7;
struct node{
int l,r;
int valu;//值
int lazy;//懒惰乘积
ll mul1;//往下传递的
ll mul2;//自己的
}no[maxn<<2];
int inv[305];
int f[65];
int s[65];//求出来300之内的素数
int vis[305];//标记素数
int cnt;
void init()
{
cnt=1;
for(int i=2;i<=300;i++)
{
if(!vis[i])
{
s[cnt++]=i;
for(int j=i+i;j<=300;j+=i)
vis[j]=1;
}
}
inv[1]=1;
for(int i=2;i<=300;i++)
inv[i]=mod-1ll*(mod/i)*inv[mod%i]%mod;
for(int i=1;i<cnt;i++)
f[i]=1ll*inv[s[i]]*(s[i]-1)%mod;
}
int qpow(int x,int y)
{
int ans=1;
while(y)
{
if(y&1)
ans=(1ll*ans*x)%mod;
x=(1ll*x*x)%mod;
y=y>>1;
}
return ans;
}
void pushup(int id,node a,node b)
{
no[id].valu=1ll*a.valu*b.valu%mod;
no[id].mul2=1ll*a.mul2|b.mul2;
}
void build(int id,int l,int r)
{
no[id].l=l;
no[id].r=r;
no[id].lazy=1;
no[id].mul1=0;
no[id].mul2=0;
if(l==r)
{
scanf("%d",&no[id].valu);
for(int i=1;i<cnt;i++)
if(no[id].valu%s[i]==0)
no[id].mul2|=(1ll<<(i-1));
return ;
}
int mid=(l+r)/2;
build(id<<1,l,mid);
build(id<<1|1,mid+1,r);
pushup(id,no[id<<1],no[id<<1|1]);
}
void pushdown(int id,ll x,ll y)
{
if(no[id].lazy)
{
no[id<<1].lazy=(1ll*no[id<<1].lazy*x)%mod;
no[id<<1|1].lazy=(1ll*no[id<<1|1].lazy*x)%mod;
no[id<<1].mul1|=y;
no[id<<1|1].mul1|=y;
no[id<<1].mul2|=y;
no[id<<1|1].mul2|=y;
no[id<<1].valu=(1ll*no[id<<1].valu*qpow(x,no[id<<1].r-no[id<<1].l+1))%mod;
no[id<<1|1].valu=(1ll*no[id<<1|1].valu*qpow(x,no[id<<1|1].r-no[id<<1|1].l+1))%mod;
no[id].lazy=1;
no[id].mul1=0;
}
}
void update(int id,int l,int r,ll x,ll y)
{
if(no[id].l>=l && no[id].r<=r)
{
no[id].valu=(1ll*no[id].valu*qpow(x,no[id].r-no[id].l+1))%mod;
no[id].mul1|=y;
no[id].mul2|=y;
no[id].lazy=(1ll*no[id].lazy*x)%mod;
return ;
}
pushdown(id,no[id].lazy,no[id].mul1);
int mid=(no[id].l+no[id].r)/2;
if(l<=mid)
update(id<<1,l,r,x,y);
if(r>mid)
update(id<<1|1,l,r,x,y);
pushup(id,no[id<<1],no[id<<1|1]);
}
node query(int id,int l,int r)
{
if(no[id].l>=l && no[id].r<=r)
{
return no[id];
}
pushdown(id,no[id].lazy,no[id].mul1);
int mid=(no[id].l+no[id].r)/2;
if(r<=mid)
return query(id<<1,l,r);
if(l>mid)
return query(id<<1|1,l,r);
node xx,yy;
xx=query(id<<1,l,r);
yy=query(id<<1|1,l,r);
xx.valu=(1ll*xx.valu*yy.valu)%mod;
xx.mul2=(1ll*xx.mul2|yy.mul2);
return xx;
}
int main()
{
init();
int n,q,l,r;
char str[20];
scanf("%d%d",&n,&q);
build(1,1,n);
while(q--)
{
scanf("%s",str);
scanf("%d%d",&l,&r);
if(str[0]=='T')
{
node t = query(1,l,r);//区间积
ll ans=t.valu;
for(int i=1;i<cnt;i++)
{
if(t.mul2&(1ll<<(i-1)))
ans=1ll*ans*f[i]%mod;
}
printf("%lld\n",ans);
}
else
{
int x;
ll y=0;
scanf("%d",&x);
for(int i=1;i<cnt;i++)
if(x%s[i]==0)
y+=(1ll<<(i-1));
update(1,l,r,x,y);
}
}
return 0;
}
补题结束~