A: 世界线
时限: 2 Sec 内存: 256 MB
题目描述
输入格式
输出格式
输入样例
5 5
1 2
1 3
2 3
3 4
4 5
输出样例
5
提示
题解
降智好题。。。。
考场上秒切bitset求传递闭包,马上开始写,写完算一下内存发现800+MB。。。。
然后就懵了。。。。
然后删掉了bitset的代码,写了个n^2暴力
其实直接把编号分一下组,多做几次dfs就好了。。。。
降智打击。。。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<bitset>
using namespace std;
#define N 60005
#define M 100005
int fir[N],to[M],nxt[M],d[N],cnt;
void adde(int a,int b)
{
to[++cnt]=b;nxt[cnt]=fir[a];fir[a]=cnt;
}
bitset<20005>s[N];
bool vis[N];
void dfs(int u)
{
vis[u]=1;
for(int v,p=fir[u];p;p=nxt[p]){
v=to[p];
if(!vis[v]) dfs(v);
s[u]|=s[v];
}
}
int sum[N];
int main()
{
//freopen("worldline.in","r",stdin);
//freopen("worldline.out","w",stdout);
int n,m,i,u,v;
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++){
scanf("%d%d",&u,&v);
adde(u,v);d[u]++;
}
int l=1,r=20000;
while(l<=n){
memset(vis,0,sizeof(vis));
for(i=1;i<=n;i++){
s[i]&=s[0];
if(i>=l&&i<=r) s[i].set(i-l+1);
}
for(i=1;i<=n;i++){
if(!vis[i]) dfs(i);
sum[i]+=s[i].count();
}
l+=20000;r+=20000;
}
long long ans=0;
for(i=1;i<=n;i++)
ans+=sum[i]-d[i]-1;
printf("%lld",ans);
}
B: 时间机器
时限: 2 Sec 内存: 256 MB
题目描述
输入格式
输出格式
输入样例
3
2 2
1 4 2
3 5 1
1 4 2
2 5 1
3 2
1 3 1
2 4 1
3 5 1
1 3 2
2 5 1
2 2
1 2 2
1 2 1
1 2 1
1 2 2
输出样例
Yes
No
Yes
提示
题解
基础贪心(又被降智了。。。。)
满足一个节点的需求的必要条件是:一类电阻左端点小于该节点
当我们按左端点排序后,右端点就决定了当前电阻的适应力
显然,贪心地想一下,我们一个取适应力尽量小又满足条件的电阻,这样就可以为后面的选择留出更大的空间
然后set维护一下就好了
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
using namespace std;
inline int gi()
{
char c;int num=0,flg=1;
while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1;
while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
return num*flg;
}
#define N 50005
struct node{
int l,r,x,id;
}a[N],b[N];
bool cmp(node q,node w){return q.l<w.l||(q.l==w.l&&q.r<w.r);}
struct nod{
int r,x,id;
nod(){}
nod(int w,int q,int e){r=w;x=q;id=e;}
bool operator < (const nod &t)const{
return r<t.r||(r==t.r&&id<t.id);
}
}tmp;
set<nod> s;
set<nod>::iterator it1,it2,tit;
int main()
{
//freopen("machine.in","r",stdin);
//freopen("machine.out","w",stdout);
int T,n,m,i,j;
T=gi();
while(T--){
s.clear();
n=gi();m=gi();
for(i=1;i<=n;i++){a[i].l=gi();a[i].r=gi();a[i].x=gi();}
for(i=1;i<=m;i++){b[i].l=gi();b[i].r=gi();b[i].x=gi();b[i].id=i;}
sort(a+1,a+n+1,cmp);sort(b+1,b+m+1,cmp);
bool flg=0;
for(i=1,j=1;i<=n;i++){
while(j<=m&&b[j].l<=a[i].l){
s.insert(nod(b[j].r,b[j].x,b[j].id));
j++;
}
it1=s.lower_bound(nod(a[i].r,0,0));
while(a[i].x&&it1!=s.end()){
if((*it1).x<=a[i].x){
a[i].x-=(*it1).x;
tit=it1;it1++;s.erase(tit);
}
else{
tmp=(*it1);tit=it1;it1++;s.erase(tit);
tmp.x-=a[i].x;s.insert(tmp);a[i].x=0;
}
}
if(a[i].x&&it1==s.end()){printf("No\n");flg=1;break;}
}
if(!flg) printf("Yes\n");
}
}
问题 C: 密码
时限: 1 Sec 内存: 256 MB
题目描述
输入格式
输出格式
输入样例
4 2 2
输出样例
2
提示
题解
题意就是求:
数位DP。。。确实没想到(我太菜了2333)库默尔定理了解一下(其实也不太需要)
我们先展开一下组合数:
一个 包含了多少个因子p呢?
那么一个组合数C(n,m)呢?
如果我们把n,m,n-m都表示成为p进制下的数的话
就会发现上面的式子表示:在截掉n,m,n-m的后i位,只把前面的剩下部分n',m',(n-m)'来计算n'-m'-(n-m)'
又因为m+(n-m)=n
所以C(n,m)中包含的因子p的个数就是m+(n-m)在p进制下的进位次数(如果要看严谨的证明可以去百度)
有了这个性质我们就可以数位DP了
先把N转为p进制数
设f[i][j][0/1][0/1]为前i位,已经进位了j次,下一位是否进位,和前i位是否与限制相等
然后发现前一位转移到当前位的贡献是一个等差数列的和,可以直接算
于是就没了。。。
std:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#define For(i, j, k) for(int i = j; i <= k; i++)
#define Forr(i, j, k) for(int i = j; i >= k; i--)
using namespace std;
const int N = 3510;
const int Mod = 1000000007;
typedef long long LL;
char S[N];
LL A[N], C[N], l;
int n, p, e;
int dp[N][N][2][2];
void divide(){
LL s = 0;
Forr(i, l, 1){
s += A[i];
A[i] = s / p, s %= p;
s *= 10;
}
while(!A[l] && l > 0) --l;
C[++n] = s / 10;
}
inline LL calc(int x){
return (1LL * x * (x + 1) / 2) % Mod;
}
int main(){
freopen("password.in", "r", stdin);
freopen("password.out", "w", stdout);
scanf("%s%d%d", S + 1, &p, &e);
l = strlen(S + 1);
Forr(i, l, 1) A[l + 1 - i] = S[i] - '0';
while(l) divide();
if(e > n){puts("0"); return 0;}
reverse(C + 1, C + n + 1);
dp[0][0][0][1] = 1;
For(i, 0, n - 1) For(j, 0, e)
For(k, 0, 1){
int cx = dp[i][j][k][0], cy = dp[i][j][k][1];
For(v, 0, 1){
int nj = j == e ? j : j + v;
int &nx = dp[i + 1][nj][v][0], &ny = dp[i + 1][nj][v][1];
if(!k){
nx = (nx + 1LL * cx * calc(p - v)) % Mod;
nx = (nx + 1LL * cy * calc(C[i + 1] - v)) % Mod;
ny = (ny + 1LL * cy * (C[i + 1] - v + 1)) % Mod;
}
else{
nx = (nx + 1LL * cx * calc(p + v - 1)) % Mod;
nx = (nx + 1LL * cy * (calc(p + v - 1) - calc(p - C[i + 1] + v - 1) + Mod)) % Mod;
ny = (ny + 1LL * cy * (p - C[i + 1] + v - 1)) % Mod;
is this!!!
}
}
}
printf("%d\n", (dp[n][e][0][0] + dp[n][e][0][1]) % Mod);
return 0;
}