题目:链接
A. An Olympian Math Problem
输出n-1即可(女朋友猜的)。
#include
using namespace std;
#define ll long long
ll fac[103];
int main()
{
ll n,T;cin>>T;
while(T--)
{
cin>>n;
cout<
B. The writing on the wall
枚举矩形的右下角,设为(x,y),若以(x,y)为右下角,设y这一行小于x且离x最近的一个空地坐标为L,
则以(x,y)为右下角可以形成宽度为1的矩形(x-L)个,以(x,y)为右下角可以形成宽度为2的矩形数量为
y行与y-1行的x-L取个min。遍历一遍宽度即可。虽说理论上是10亿的复杂度,可能判题机跑的比较快吧。
也可能数据较水。
代码:
#include
using namespace std;
#define ll long long
const int maxn=1e5+10;
vectorG[maxn];
int n,m,k;
int L[maxn],iter[maxn],len[maxn];
int main()
{
int T,cas=0;scanf("%d",&T);
while(T--)
{
scanf("%d%d%d",&n,&m,&k);
for(int i=0;i<=n;i++) G[i].clear();
while(k--)
{
int x,y;scanf("%d%d",&x,&y);
G[y].push_back(x);
}
for(int i=1;i<=m;i++)
{
len[i]=G[i].size();
sort(G[i].begin(),G[i].end());
iter[i]=0;L[i]=0;
}
ll ans=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(iter[j]=1;k--)
{
mi=min(mi,i-L[k]);
ans+=mi;
if(mi==0) break;
}
}
}
printf("Case #%d: %lld\n",++cas,ans);
}
return 0;
}
E. AC Challenge
状压dp,对于每个状态判断是否合法(即若i在集合中,则i所依赖的题目也要在集合中),
若此状态合法,则用它的上一步状态来更新此状态。
代码:
#include
using namespace std;
#define ll long long
const int maxn=22;
ll a[maxn],b[maxn];
ll dp[1<<21];
vectorG[maxn];
int main()
{
for(int i=0;i<(1<<21);i++) dp[i]=-1e18;
dp[0]=0;
int n;scanf("%d",&n);
for(int i=0;i>i&1)) continue;
for(int j=0;j>G[i][j]&1)) bb=1;
if(bb) break;
}
if(bb) continue;
for(int i=0;i>i&1)) continue;
int t=0,S=s;
while(S)
{
if(S&1) t++;
S/=2;
}
dp[s]=max(dp[s],dp[s^(1<
G. Lpl and Energy-saving Lamps
对于当前的s从左到右找到第一个小于等于s的a[i],让后将a[i]个灯泡换成新的,a[i]改为inf。
然后灯泡数量s=s-a[i]。线段树维护即可。
#include
using namespace std;
const int maxn=1e5+10;
int n,k,Q,s;
int a[maxn],tree[maxn<<2],ans1[maxn],ans2[maxn];
void build(int l,int r,int rt)
{
if(l==r)
{
tree[rt]=a[l];
return;
}
int mid=(l+r)/2;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
tree[rt]=min(tree[rt<<1],tree[rt<<1|1]);
}
int query(int C,int l,int r,int rt)
{
if(l==r)
{
s-=a[l];
return l;
}
int mid=(l+r)/2;
if(tree[rt<<1]<=C) return query(C,l,mid,rt<<1);
else return query(C,mid+1,r,rt<<1|1);
}
void update(int L,int l,int r,int rt)
{
if(l==r)
{
tree[rt]=2e9;
return;
}
int mid=(l+r)/2;
if(L<=mid) update(L,l,mid,rt<<1);
else update(L,mid+1,r,rt<<1|1);
tree[rt]=min(tree[rt<<1],tree[rt<<1|1]);
}
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
build(1,n,1);
s=0;
for(int i=1;i<=100000;i++)
{
s+=k;
ans1[i]=ans1[i-1];
while(s>=tree[1])
{
ans1[i]++;
int id=query(s,1,n,1);
update(id,1,n,1);
}
ans2[i]=s;
if(tree[1]==2e9)
{
for(int j=i+1;j<=100000;j++)
{
ans1[j]=ans1[i];
ans2[j]=ans2[i];
}
break;
}
}
scanf("%d",&Q);
while(Q--)
{
int t;scanf("%d",&t);
printf("%d %d\n",ans1[t],ans2[t]);
}
return 0;
}
J. Sum
把每个数拆成素数相乘。
设x=(a[1]^b[1])*(a[2]^b[2])*(a[3]^b[3])....
其中a[i]为质数,b[i]为指数,
然后令x=n*m,
n=(a[1]^b1[1])*(a[2]^b1[2])*(a[3]^b1[3])...
m=(a[1]^b2[1])*(a[2]^b2[2])*(a[3]^b2[3])...
则有b[1]=b1[1]+b2[1],b[2]=b1[2]+b2[2],b[3]=b1[3]+b2[3]...
问题转化成有几种合法方法分配b1,b2两个数组。
对于x的所有b[i],若存在b[i]>2,则一定无法合理安排。
因为b1[i]和b2[i]中一定有一个大于2,这样n和m至少有
一个数字含有一个完全平方数的约数。
假设b1[i]>2,则一定有n=t*a[i]^2,因此n不合法。
若b[i]=2,则只有b1[i]=1,b2[i]=1,一种选择。
若b[i]==1,则可以b1[i]=0,b2[i]=1或b1[i]=1,b2[i]=0。
代码:
#include
#include
using namespace std;
#define ll long long
const int maxn=20000005;
int a[maxn],b[maxn];
bool vis[maxn];
int p[maxn],q[maxn],pp[maxn];
int sum[maxn];
void init()
{
int len=0;
a[1]=1;
for(int i=2;i2) break;
}
if(k>2) a[i]=0;
else if(k==2) a[i]=a[x];
else a[i]=2*a[x];
}
sum[i]=sum[i-1]+a[i];
}
}
int main()
{
init();
int T;scanf("%d",&T);
while(T--)
{
int n;scanf("%d",&n);
printf("%d\n",sum[n]);
}
return 0;
}
L. Magical Girl Haze
把每个点拆成k+1个点建立分层图,对于第i个点,拆成i,i+n,i+2*n...i+k*n
若原图中i~j有一条权值为x的边,则
add_edge(i,j,x),add_edge(i+n,j+n,x).....add_edge(i+k*n,j+k*n,x)
add_edge(i,j+n,0),add_edge(i+n,j+2*n,0)....add_edge(i+(k-1)*n,j+k*n,0)
每向上走一层相当于走了一条权值为0的边,
假设走了(i,j+n,0)相当于从第0层走到了第一层,而把i~j这条边的权值改为0。
最后输出1~(k+1)*n的最短路即可。
代码:
#include
using namespace std;
const int mn = 1400010, mm = 5000010;
const long long inf = 1e18;
int n, m, k;
int num;
int from[mm], to[mm], nx[mm], fr[mm];
long long cost[mm];
void addedge(int a, int b, long long c)
{
for (int i = 0; i <=k; i++)
{
num++;
from[num] = a + i * n;
to[num] = b + i * n;
cost[num] = c;
nx[num] = fr[a + i * n];
fr[a + i * n] = num;
}
for (int i = 0; i < k ; i++)
{
num++;
from[num] = a + i * n;
to[num] = b + (i + 1) * n;
cost[num] = 0;
nx[num] = fr[a + i * n];
fr[a + i * n] = num;
}
}
struct node
{
int id;
long long w;
friend bool operator < (struct node a, struct node b)
{
return a.w > b.w;
}
} dis[mn];
priority_queueq;
void dijkstra(int a)
{
for (int i = 1; i < mn; i++)
{
dis[i].id = i;
dis[i].w = inf;
}
dis[a].w = 0;
q.push(dis[a]);
while (!q.empty())
{
node cd = q.top();
q.pop();
for (int i = fr[cd.id]; i != -1; i = nx[i])
{
int v = to[i];
if (dis[v].w > dis[cd.id].w + cost[i])
{
dis[v].w = dis[cd.id].w + cost[i];
q.push(dis[v]);
}
}
}
}
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
num = 0;
memset(fr, -1, sizeof fr);
scanf("%d %d %d", &n, &m, &k);
while (m--)
{
int a, b;
long long c;
scanf("%d %d %lld", &a, &b, &c);
addedge(a, b, c);
}
dijkstra(1);
printf("%lld\n", dis[k * n + n].w);
}
return 0;
}