算一下两个数,取最小的
#include
using namespace std;
const int nmax = 1e6 ;
const int INF = 0x3f3f3f3f;
typedef long long ll;
typedef double db;
ll n,m;
ll a,b;
int main() {
scanf("%I64d%I64d%I64d%I64d",&n,&m,&a,&b);
if(n % m == 0){
printf("0\n");
}else{
ll temp = n / m;
ll f = temp * m;
ll bb = (temp + 1) * m;
ll ans1 = abs(f - n) * b;
ll ans2 = abs(bb - n) * a;
printf("%I64d\n",min(ans1,ans2));
}
return 0;
}
一开始想想着排序,然后在里面数组里面二分,然后发现二分不会写我凑,最后用双指针乱搞。
我这里用的优先队列实现的,复杂度 O(nlogn) O ( n l o g n )
#include
using namespace std;
const int nmax = 1e6 + 100;
const int INF = 0x3f3f3f3f;
typedef long long ll;
typedef double db;
int n,k;
priority_queuevector, greater > pq1, pq2;
int main() {
scanf("%d %d",&n,&k);
int temp;
for(int i = 1;i<=n;++i){
scanf("%I64d",&temp);
pq1.push(temp);
pq2.push(temp);
}
int ans = 0;
while(pq1.top() == pq2.top()){
pq1.pop();
if(pq1.empty()) break;
}
while(1){
if(pq1.empty()) break;
int now = pq1.top();
while(1){
if(pq2.empty()) {pq1.pop();break;}
if(now - pq2.top()<=k && now - pq2.top() >0){
ans ++;
pq2.pop();
}else if(now == pq2.top()){
pq1.pop();
break;
}else{
pq2.pop();
}
}
}
printf("%d\n",n - ans);
return 0;
}
一个不难的计数问题。求问有多少组合法的括号能两两组队。
首先对括号进行处理,求出单边的括号序列,单边的意思是,对于这个括号序列,在其一边添加上另外一组单边的括号序列,即可组成合法序列。
如(()就是左单边序列,而()()()(())))就是右单边序列,而)(((())就不是单边序列。
处理出所有单边序列的需要匹配的个数,如(()就是左1,他的右边匹配一个右1就是合法序列了,
而对于()()()(())))就是右2,他的左边匹配一个左2就是合法序列了。
最后统计答案即可
#include
using namespace std;
const int nmax = 3*1e5 + 100 ;
const int INF = 0x3f3f3f3f;
typedef long long ll;
char str[nmax];
int l[nmax];
int r[nmax];
vector<char> ss;
int n;
int main() {
scanf("%d",&n);
int mx = -1;
ll ans = 0;
for(int i = 1;i<=n;++i){
scanf("%s",str);
int len = strlen(str);
ss.clear();
for(int i = 0;iif(str[i] == '(') ss.push_back(str[i]);
else if(str[i] == ')'){
if(!ss.empty() && ss[ss.size()-1] == '('){
ss.pop_back();
}else{
ss.push_back(str[i]);
}
}
}
int lcnt = 0, rcnt =0;
for(int i = 0;iif(ss[i] == '(') lcnt++;
else if(ss[i] == ')') rcnt++;
}
mx = max(mx,max(rcnt,lcnt));
if(lcnt == 0 && rcnt !=0 ){
r[rcnt] ++;
}else if(rcnt == 0 && lcnt != 0){
l[lcnt] ++;
}else if(rcnt == 0 && rcnt == 0){
l[lcnt] ++;
r[rcnt] ++;
}
}
ans += (ll)l[0] * (ll)r[0];
for(int i = 1;i<=mx;++i){
ans += (ll)l[i] * (ll)r[i];
}
printf("%I64d\n",ans);
return 0;
}
求一个n个点的无向图邻接矩阵,要求原图有a个联通分量,补图有b个联通分量。
构造,手推一下会发现,原图和补图的联通分量中一定有一个是1。得到了判断NO的条件。
另外需要注意,当n为2或者3的时候,a和b不能同时为1。
其他条件均为符合的。
由于a和b一定有一个为1,那么构造就不难了。我们只需要对不是1的那一个进行构造。
对于原图,填1,对于补图,填0。填1表示构建连接,填0表示破坏连接关系。
如n=4,a=3,b=1,只需要任选2个点连一条边这样就好了。
又如n=4,a=1,b=3,只需要任选2个点,破坏一条边就好了。
#include
using namespace std;
const int nmax = 1005;
int n,a,b;
int mat[nmax][nmax];
int main() {
scanf("%d %d %d",&n,&a,&b);
if(a!=1 && b!=1) printf("NO\n");
else if((n == 2 || n == 3) && a == 1 && b == 1) printf("NO\n");
else{
printf("YES\n");
int conta = 1, contb = 0;
if(b != 1) swap(a,b), swap(conta,contb);
for(int i = 1;i<=n;++i)
for(int j = 1;j<=n;++j)
if(i != j) mat[i][j] = mat[j][i] = contb;
for(int i = a ;i <=n;++i)
mat[i][i+1] = mat[i+1][i] = conta;
for(int i = 1;i<=n;++i){
for(int j = 1;j<=n;++j){
printf("%d",mat[i][j]);
}
printf("\n");
}
}
return 0;
}