先写下昨晚context的题解吧
数据没拉满,n^2可以过,我讲下nlogn的写法
排序后,用双指针head tail 搞下去 计算贡献
#include <bits/stdc++.h>
using namespace std;
const int mac=1e3+10;
int a[mac];
int main()
{
int n,k;
scanf ("%d%d",&n,&k);
for (int i=1; i<=n; i++)
scanf ("%d",&a[i]);
sort(a+1,a+1+n);
int head=1,tail=1;
int ans=1;
while (tail<=n){
while (a[tail]-a[head]<=k && tail<=n) tail++;
if (a[tail]-a[head]<=k && tail<=n) ans=max(ans,tail-head+1);
else ans=max(ans,tail-head);
head++;
}
printf("%d\n",ans);
return 0;
}
意思是给两个三位数的字符串 每位0–9 他们表示同一个数的不同进制下的表达,要我们确定是哪个进制。
解析:我们枚举一个数的进制,然后二分另外一个数的进制 就OK了
char s1[5];
char s2[5];
ll ex(ll i)
{
ll cnt=0;
for(int rnm=1; rnm<=3; rnm++)
{
cnt=cnt*i+(s1[rnm]-'0');
}
return cnt;
}
bool check(ll num,ll bit)
{
ll cnt=0;
for(int rnm=1; rnm<=3; rnm++)
{
cnt=cnt*bit+(s2[rnm]-'0');
}
if(cnt>=num)
{
return true;
}
return false;
}
signed main()
{
ll t;
read(t);
while(t--)
{
scanf("%s%s",s1+1,s2+1);
for(int i=10; i<=15000; i++)
{
ll x=ex(i);
ll l=9,r=15001;
while(l<r)
{
ll mid=(l+r)/2;
if(check(x,mid))
{
r=mid;
}
else
{
l=mid+1;
}
}
if(l<10||l>15000)
continue;
ll op=0;
op=op*l+(s2[rnm]-'0');
}
if(op==x)
{
printf("%lld %lld\n",i,l);
break;
}
}
}
}
意思是建图以后,询问两个人有没有到达n点的时间是一样的 取最小。n<=16可以暴力搜索,也可以拓扑dp (( 好像跟k短路有关系
ll map1[600][600],map2[600][600];
ll s[600],top,deep[600];
ll dp[20][30000][3];
signed main()
{
memset(map1,-1,sizeof map1);
memset(map2,-1,sizeof map2);
ll n,m;
read(n);
read(m);
for(int i=1;i<=m;i++){
ll u,v,w1,w2;
read(u);
read(v);
read(w1);
read(w2);
map1[u][v]=w1;
map2[u][v]=w2;
deep[v]++;
}
for(int i=1;i<=n;i++)if(deep[i]==0)s[++top]=i;
dp[1][0][0]=1;
dp[1][0][1]=1;
while(top)
{
ll rnm=s[top--];
for(int i=1; i<=n; i++)
{
if(map1[rnm][i]>0)
{
deep[i]--;
if(deep[i]==0) s[++top]=i;
//16* 1000
for(int j=map1[rnm][i]; j<=20000; j++)
dp[i][j][0]|=dp[rnm][j-map1[rnm][i]][0];
for(int j=map2[rnm][i]; j<=20000; j++)
dp[i][j][1]|=dp[rnm][j-map2[rnm][i]][1];
}
}
}
for(int i=0;i<=20000;i++)
{
if(dp[n][i][0]&dp[n][i][1])
{
printf("%lld\n",i);
return 0;
}
}
puts("IMPOSSIBLE");
return 0;
}
n<=500 考虑到只能走两条线,要么是一条直达,要么转机,直接模拟就OK了,注意转机点的序号
ll a[2000][550];
ll num[2200];
ll cost[2200];
ll visu[2200];
ll visv[2200];
map<pair<ll,ll>,ll>sb;
signed main()
{
ll u,v,n;
read(u);
read(v);
read(n);
ll ans=1e18;
ll op=0;
for(int i=1; i<=n; i++)
{
read(cost[i]);
read(num[i]);
for(int j=1; j<=num[i]; j++)
{
read(a[i][j]);
sb[ {
i,a[i][j]}]=j;
if(a[i][j]==u)
{
visu[i]=j;
}
if(a[i][j]==v)
{
visv[i]=j;
}
}
if(visu[i]!=0&&visv[i]!=0&&visu[i]<visv[i])
{
ans=min(ans,cost[i]);
op++;
}
}
for(int i=1; i<=n; i++)
{
if(visu[i]==0)
{
continue;
}
for(int j=1; j<=n; j++)
{
if(i==j||visv[j]==0)
{
continue;
}
for(int k=visu[i]; k<=num[i]; k++)
{
if(sb[ {
j,a[i][k]}]!=0&&sb[ {
j,a[i][k]}]<visv[j])
{
ans=min(ans,cost[i]+cost[j]);
op++;
}
}
}
}
if(op==0)
{
printf("-1");
return 0;
}
printf("%lld\n",ans);
}
这个我是打表过的QAQ 不会正解,希望大佬可以指点下
----------- 早上写篇题解再刷几个杂题吧 下午复习下
div2 495 做出来4个
AB太水了
C题
给了我们一个长度为n的序列,定义(a,b) 当b的下标>a的下标才合法,求有多少种合法二元组。我们分析,要考虑到重复性,如果正向枚举,那么这个数的所有方案数就是它后面的不同的数的个数,而且每个数只能算一次,那么先倒着预处理一次后缀 sum i 表示 n到i+1 有多少个不同的数
const int maxn = 1e5 + 7;
int n;
set<int> s, t;
int a[maxn], sum[maxn];
signed main() {
ll n;
read(n);
for(int i = 0; i < n; i++) {
read(a[i]);
}
for(int i = n - 1; i >= 0; i--) {
sum[i] = s.size();
if(!s.count(a[i])) {
s.insert(a[i]);
}
}
long long ans = 0;
for(int i = 0; i < n; i++) {
if(t.count(a[i])) continue;
t.insert(a[i]);
ans += sum[i];
}
printf("%lld",ans);
return 0;
}
D题 思维+模拟 题意自己慢慢看吧,考虑到扩散,我们可以得知最多可以扩散多少圈,那么可以确定0点的x 或者y 坐标, 顺着模拟check吧