首先需要写个暴力最小生成树的模板。
然后我们可以把题目给的样例试一下,然后不难发现大多数情况答案为 n − 1 n-1 n−1,但是需要注意一个特殊情况:当 L = = R L==R L==R时,答案只能为 L ∗ ( n − 1 ) L*(n-1) L∗(n−1)。
我们接着打表找规律可以发现,只有当 n < = 5 n<=5 n<=5答案可能会发生变化,这种情况我们直接暴力建树跑最小生成树即可。
#include
#define PI atan(1.0)*4
#define rp(i,s,t) for ( int i = (s); i <= (t); i++)
#define RP(i,t,s) for ( int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define pii pair
#define pll pair
#define pil pair
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define pY puts("YES")
#define pN puts("NO")
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
#define outval2(a,b) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b << "\n";
#define outval3(a,b,c) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b <<"\t"<< #c << ": " << c << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
return a/gcd(a,b)*b;
}
inline int read(){
int s=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
s=s*10+ch-'0';
ch=getchar();
}
return s*f;
}
const int N = 2e5+7;
int a[N];
int n,L,R;
ull seed;
ull xorshift64(){
ull x=seed;
x^=x<<13;
x^=x>>7;
x^=x<<17;
return seed=x;
}
int gen(){
return xorshift64()%(R-L+1)+L;
}
struct edge{
int u,v,w;
}e[N*2];
int fa[N],tot;
int find(int x){return x==fa[x]?fa[x]:fa[x]=find(fa[x]);}
void init(){
rp(i,1,n) fa[i]=i;
}
void Kruskal(){
sort(e+1,e+1+tot,[&](edge a,edge b){
return a.w<b.w;
});
int cnt=0;
ull ans=0;
rp(i,1,tot){
if(cnt==n-1) break;
int fu=find(e[i].u),fv=find(e[i].v);
if(fu!=fv){
fa[fu]=fv;
ans+=e[i].w;
}
}
cout<<ans<<endl;
}
void solve(){
cin>>n>>L>>R>>seed;
rp(i,1,n){
a[i]=gen();
// outval2(i,a[i]);
}
init();
if(n<7){
rp(i,1,n) rp(j,i+1,n) e[++tot]=edge{i,j,__gcd(a[i],a[j])};
Kruskal();
}
else{
if(L==R) cout<<1ll*L*(n-1)<<endl;
else cout<<n-1<<endl;
}
// if(seed==1) cout<<2*(n-1)<
// else cout<
}
int main(){
//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
freopen("in.txt", "r", stdin);
//debug = 1;
#endif
//time_t beg, end;
//if(debug) beg = clock();
solve();
/*
if(debug) {
end = clock();
printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
*/
return 0;
}
也是个比较巧妙的构造,队友(构造小能手)最后构造出来了(orz)。
不过样例给的暗示也够强了(虽然我没看出来)。
首先需要发现两个规律,第一个是每多一个兄弟节点贡献会乘上 2 2 2,而每多一个儿子节点贡献会加 1 1 1。
因此我们可以对一个数不断的进行分解。
当这个数 k k k是奇数时,我们可以把在当前节点加一个叶子节点(贡献为 1 1 1)和一个非叶节点(权值为 k 2 \frac{k}{2} 2k),然后对这个非叶节点进行递归子问题处理就行了。
当这个数 k k k是偶数时,我们可以通过给这个节点加一个儿子节点(权值为 k − 1 k-1 k−1),又转换成了奇数的情况。
直接模拟整个过程就行了。
注意当 k = 3 k=3 k=3是只需要加一个儿子节点(权值为 2 2 2)就行了。
t r i c k trick trick:需要特判 k = = 2 k==2 k==2的情况。
#include
#define PI atan(1.0)*4
#define rp(i,s,t) for (int i = (s); i <= (t); i++)
#define RP(i,t,s) for (int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define pii pair
#define pll pair
#define pil pair
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define pY puts("YES")
#define pN puts("NO")
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
#define outval2(a,b) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b << "\n";
#define outval3(a,b,c) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b <<"\t"<< #c << ": " << c << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
return a/gcd(a,b)*b;
}
inline int read(){
int s=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
s=s*10+ch-'0';
ch=getchar();
}
return s*f;
}
const int N = 2e5+7;
int a[N];
void solve(){
ll k;scl(k);
if(k==2){
cout<<1<<endl;
return ;
}
int pre=1;
int cur=1;
vector<pii> res;
while(k>2){
if(k&1){
if(k==3){
cur++;
res.push_back(m_p(pre,cur));
break;
}
cur++;
res.push_back(m_p(pre,cur));
cur++;
res.push_back(m_p(pre,cur));
pre=cur;
k/=2;
}
else{
cur++;
res.push_back(m_p(pre,cur));
pre=cur;
k--;
}
}
cout<<cur<<endl;
for(auto val:res) cout<<val.first<<" "<<val.second<<endl;
}
int main(){
//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
// freopen("in.txt", "r", stdin);
//debug = 1;
#endif
//time_t beg, end;
//if(debug) beg = clock();
solve();
/*
if(debug) {
end = clock();
printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
*/
return 0;
}
模拟整个过程,每加一个矩形就算一下他对答案的贡献即可。
设一个矩形四个方向上有 c n t cnt cnt个矩形
一个矩形的贡献就是 4 − 2 ∗ c n t 4-2*cnt 4−2∗cnt。
这里分为两种情况置矩形。
对于收到竖直重力影响的,我们需要记录其 x x x轴坐标,对于 y y y轴坐标,等于它之前和它 x x x轴坐标相同的矩形个数。
水平重力的类比上面。
#include
#define PI atan(1.0)*4
#define rp(i,s,t) for ( int i = (s); i <= (t); i++)
#define RP(i,t,s) for ( int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define pii pair
#define pll pair
#define pil pair
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define pY puts("YES")
#define pN puts("NO")
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
#define outval2(a,b) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b << "\n";
#define outval3(a,b,c) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b <<"\t"<< #c << ": " << c << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
return a/gcd(a,b)*b;
}
inline int read(){
int s=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
s=s*10+ch-'0';
ch=getchar();
}
return s*f;
}
const int N = 2e5+7;
int xx[N],yy[N];
void solve(){
int n=read();
ll ans1=0,ans2=0;
rp(i,1,n){
int x=read(),y=read();
int num1=xx[x]?1:0;
xx[x]++;
if(x>0&&xx[x-1]>=xx[x]) num1++;
if(xx[x+1]>=xx[x]) num1++;
ans1=ans1+4-2*num1;
int num2=yy[y]?1:0;
yy[y]++;
if(y>0&&yy[y-1]>=yy[y]) num2++;
if(yy[y+1]>=yy[y]) num2++;
ans2=ans2+4-2*num2;
printf("%lld %lld\n",ans1,ans2);
}
}
int main(){
//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
freopen("in.txt", "r", stdin);
//debug = 1;
#endif
//time_t beg, end;
//if(debug) beg = clock();
solve();
/*
if(debug) {
end = clock();
printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
*/
return 0;
}
待补。
刚开始队友用 p y t h o n python python的 D e c i m a l Decimal Decimal莽了几发(其实自己也想用 J a v a Java Java的 B i g D e c i m a l BigDecimal BigDecimal),但是都没过,发现可能思路错了,后面发现可以直接模拟除法就行了。
#include
#define PI atan(1.0)*4
#define rp(i,s,t) for ( int i = (s); i <= (t); i++)
#define RP(i,t,s) for ( int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define pii pair
#define pll pair
#define pil pair
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define pY puts("YES")
#define pN puts("NO")
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
#define outval2(a,b) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b << "\n";
#define outval3(a,b,c) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b <<"\t"<< #c << ": " << c << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
return a/gcd(a,b)*b;
}
inline int read(){
int s=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
s=s*10+ch-'0';
ch=getchar();
}
return s*f;
}
const int N = 2e5+7;
int a[N];
void solve(){
int n=read(),k=read();
int sum=0;
rp(i,1,n) a[i]=read(),sum+=a[i];
string res=to_string(sum/n)+".";
sum=sum%n;
int val=sum;
int num=n;
while(k--) {
int cur=(val*10)/num;
res+=to_string(cur);
val=(val*10)%num;
}
cout<<res<<endl;
}
int main(){
//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
freopen("in.txt", "r", stdin);
//debug = 1;
#endif
//time_t beg, end;
//if(debug) beg = clock();
solve();
/*
if(debug) {
end = clock();
printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
*/
return 0;
}
背包 d p dp dp魔改题,这里只说一下状态和状态转移。
状态:
d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k]表示前i个怪物,血量为j,维他命值为k的最大金币个数。
状态转移方程:
考虑第 i i i个怪物杀和不杀两种情况。
当不杀第 i i i个怪物时
d p [ i ] [ j ] [ k ] = d p [ i − 1 ] [ j ] [ k ] dp[i][j][k]=dp[i-1][j][k] dp[i][j][k]=dp[i−1][j][k]
当杀第 i i i个怪物时,又分为三种情况。‘
1.血量够且维他命值也够
d p [ i ] [ j ] [ k ] = d p [ i − 1 ] [ j − a [ i ] . h ] [ k − a [ i ] . s ] + a [ i ] . w dp[i][j][k]=dp[i-1][j-a[i].h][k-a[i].s]+a[i].w dp[i][j][k]=dp[i−1][j−a[i].h][k−a[i].s]+a[i].w
2.血量够但是维他命值不够,但是可以通过消耗血量来抵消维他命值。
令 d e l t a = a [ i ] . s − k delta=a[i].s-k delta=a[i].s−k为需要多余消耗的血量。
d p [ i ] [ j ] [ k ] = d p [ i − 1 ] [ j − a [ i ] . h − d e l t a ] [ 0 ] + a [ i ] . w dp[i][j][k]=dp[i-1][j-a[i].h-delta][0]+a[i].w dp[i][j][k]=dp[i−1][j−a[i].h−delta][0]+a[i].w
3.对于其他情况不需要处理。
我们这时还可以进行空间的优化压缩掉第一维。
#include
#define sc(x) scanf("%lld", &x)
using namespace std;
long long n, H, S;
struct poi{
long long h, s, w;
poi() {
sc(h), sc(s), sc(w);
}
void ou() {
cout<<h<<" "<<s<<" "<<w<<"\n";
}
};
vector<poi> a;
long long dp[305][305];
int main(){
// freopen("in.txt", "r", stdin);
sc(n); sc(H), sc(S);
for(long long i = 0; i < n; ++i) {
a.push_back(poi());
}
for(long long i = 0; i < n; ++i) {
for(long long j = H; j > a[i].h; --j) {
for(long long k = S; k >= 0; --k) {
if(a[i].s>k){
long long delta=a[i].s-k;
if(j>a[i].h+delta)
dp[j][k]=max(dp[j][k],dp[j-a[i].h-delta][0]+a[i].w);
}
else{
dp[j][k]=max(dp[j][k],dp[j-a[i].h][k-a[i].s]+a[i].w);
}
}
}
}
printf("%lld\n", dp[H][S]);
return 0;
}
刚开始想的是直接 b f s + d f s bfs+dfs bfs+dfs的,但是后面发现没有完美的策略,不过队友发现可以巧妙的构造出一个解。
这个巧妙的构造是基于题目给的限制条件
1.第 1 1 1行和第 n n n行都为 0 0 0。
2.第 1 1 1列和第 m m m列都为 0 0 0。
我们就可以根据这个限制条件做文章。
首先构造符合条件的 A A A数组。
先把奇数行的都染成 1 1 1(除了第 1 1 1列的),然后把偶数行的第 m m m列都染成 1 1 1。
这个不难发现可以保证所有 1 1 1的都联通。
类比我们可以构造出 B B B数组。
先把偶数行的都染成 1 1 1(除了第 m m m列的),然后把奇数行的第 1 1 1列都染成 1 1 1。
不难发现这个方案是合法的,因为 A A A和 B B B数组中染成 1 1 1的部分的加起来恰好对应题目给的限制条件。
至于为什么这么想?(注意到限制条件应该不难想出)
#include
#define PI atan(1.0)*4
#define rp(i,s,t) for (int i = (s); i <= (t); i++)
#define RP(i,t,s) for (int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define pii pair
#define pll pair
#define pil pair
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define pY puts("YES")
#define pN puts("NO")
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
#define outval2(a,b) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b << "\n";
#define outval3(a,b,c) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b <<"\t"<< #c << ": " << c << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
return a/gcd(a,b)*b;
}
inline int read(){
int s=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
s=s*10+ch-'0';
ch=getchar();
}
return s*f;
}
const int N = 5e2+7;
char s[N][N];
char A[N][N],B[N][N];
void solve(){
int n=read(),m=read();
rp(i,0,n-1) scanf("%s",s[i]);
rp(i,0,n-1){
if(i&1){
rp(j,0,m-1) A[i][j]='1';
A[i][0]='0';
}
else{
rp(j,0,m-2) A[i][j]=s[i][j];
A[i][m-1]='1';
}
}
rp(i,0,n-1){
if(i%2==0){
rp(j,0,m-1) B[i][j]='1';
B[i][m-1]='0';
}
else{
rp(j,1,m-1) B[i][j]=s[i][j];
B[i][0]='1';
}
}
rp(i,0,n-1) printf("%s\n",A[i]);
// cout<<"***************"<
rp(i,0,n-1) printf("%s\n",B[i]);
// cout<<"***************"<
// rp(i,0,n-1){
// rp(j,0,m-1){
// if(A[i][j]=='1'&&B[i][j]=='1') printf("1");
// else printf("0");
// }
// printf("\n");
// }
}
int main(){
//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
freopen("in.txt", "r", stdin);
//debug = 1;
#endif
//time_t beg, end;
//if(debug) beg = clock();
solve();
/*
if(debug) {
end = clock();
printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
*/
return 0;
}